6dce580846
Feature work on top of the initial organizer: - Videos: .mp4/.mov/.avi/.mkv/.webm/.m4v sorted into output/Movie/YYYY/MM - Profiles: reference-image thumbnail cards via a secure photoai-media:// protocol (serves only registered reference images); per-thumbnail delete; add via click, drag & drop, or paste (Ctrl+V) using webUtils.getPathForFile + a byte-based addReferenceData path for clipboard images - Presets: local person library (max 5) saved to userData; one-click apply into active profiles; reusing stored descriptors (no recompute) - Theme: dark/light with dark default (Tailwind class strategy) - i18n: ko/en table-based localization; first-run onboarding to pick language + theme; English-neutral "Unsorted" folder (was [미정]) - App menu: File/Edit/View/Window/Help, localized; Help opens a detailed, theme-aware user guide window - UI: History block scrolls internally (no whole-window scroll); threshold/concurrency tooltips; generic example name - Settings persisted to userData/settings.json; menu + renderer kept in sync - Docs: NextGen Photo AI feasibility review + Phase 0/1 roadmap All typecheck/tests (12) /build green; boot smoke verified. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
69 lines
2.9 KiB
Markdown
69 lines
2.9 KiB
Markdown
# AI Photo Organizer
|
|
|
|
얼굴 인식 + 촬영일(EXIF) 기준으로 사진을 **로컬에서** 자동 정리하는 Electron 데스크톱 앱.
|
|
클라우드 업로드 없이 내 PC 안에서만 동작한다.
|
|
|
|
> 기획·설계 문서: [docs/PRD.md](docs/PRD.md) · [docs/DECISIONS.md](docs/DECISIONS.md) · [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
|
|
|
|
## 동작 방식
|
|
|
|
1. 인물 프로필(최대 3명)과 참조 얼굴 사진을 등록한다.
|
|
2. 정리할 폴더(소스)와 결과 폴더(출력)를 고른다.
|
|
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](https://github.com/vladmandic/face-api) (WebGL) · exifr · electron-builder
|
|
|
|
3개 프로세스로 분리된 구조:
|
|
- **Main** (Node): 스캔 / EXIF / 파일 이동·복사 / 오케스트레이션
|
|
- **UI Renderer** (React): 화면 — 무거운 연산 없음
|
|
- **Inference Renderer** (숨김 창): face-api 얼굴 인식 전담
|
|
|
|
## 개발
|
|
|
|
```bash
|
|
npm install
|
|
npm run models:download # 최초 1회 — 모델 가중치 받기
|
|
npm run dev # 개발 실행 (HMR)
|
|
```
|
|
|
|
## 검증 / 빌드
|
|
|
|
```bash
|
|
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`
|
|
|
|
## 폴더 구조
|
|
|
|
```
|
|
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/ 기획·설계 문서
|
|
```
|