Skip to content

feat(ai): 원본 이미지 역검색 파이프라인 (좌측 인물 → 고화질 원본 복원) #261

@cocoyoon

Description

@cocoyoon

Summary

fashion-decode 합성 이미지의 좌측 인물 영역을 크롭한 뒤 역이미지 검색(Google Lens / Google Vision / SerpAPI / Bing Visual Search)으로 고화질 원본 사진을 찾아 R2에 아카이빙한다. seed 데이터 품질을 올리고 원본 크레딧 추적이 가능해진다.

Related:


Architecture

source_media.parse_status='parsed' AND original_status='pending'
  → 좌측 인물 영역 크롭
       a) 파싱 결과의 bbox
       b) 휴리스틱: 이미지 좌측 1/2 crop
       c) MediaPipe/YOLO 인물 detection (v2)
  → 역검색 API 호출 (SerpAPI Google Lens 권장)
       → 후보 URL 리스트 (해상도/도메인 점수화)
  → 최상위 후보 선택:
       - 해상도 ≥ 800x1200
       - 도메인 허용 리스트 (allkpop, koreaboo, artist 공식 SNS, kpop wiki, ...)
       - EXIF/워터마크 없음
  → 원본 다운로드 → R2 (`originals/{source_media_id}.{ext}`)
  → source_media_originals INSERT
  → source_media UPDATE original_status='found' | 'not_found'

스키마

ALTER TABLE warehouse.source_media
  ADD COLUMN original_status text DEFAULT 'pending' NOT NULL
    CHECK (original_status IN ('pending','searching','found','not_found','skipped'));

CREATE TABLE warehouse.source_media_originals (
    id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
    source_media_id uuid NOT NULL REFERENCES warehouse.source_media(id) ON DELETE CASCADE,
    origin_url text NOT NULL,
    origin_domain text NOT NULL,
    r2_key text NOT NULL,
    r2_url text NOT NULL,
    width int,
    height int,
    image_hash text,
    search_provider text NOT NULL,        -- 'serpapi_lens' | 'google_vision' | 'bing' | ...
    confidence_score float,                -- 0.0-1.0
    metadata jsonb,
    created_at timestamptz DEFAULT now() NOT NULL
);

CREATE INDEX idx_source_media_originals_source ON warehouse.source_media_originals(source_media_id);

역검색 Provider 비교

Provider 장점 단점
SerpAPI Google Lens Google Lens 품질, 공식 API 유료 ($75/mo~)
Google Cloud Vision — Web Detection GCP 통합, 저렴 Lens 대비 약함
Bing Visual Search API 무료 티어 한국 이미지 커버리지 약함
직접 Google 스크래핑 무료 차단 리스크

v1: SerpAPI Google Lens, v2: GCP Vision fallback


Phase

Phase 1: 크롭

  • v1: 이미지 좌측 절반 crop (합성 이미지 포맷이 일정하므로 충분)
  • v2: YOLO/MediaPipe 인물 detection 으로 정밀 bbox

Phase 2: 역검색

  • ReverseImageSearcher 추상 (provider 교체 가능)
  • search(image_bytes) → list[SearchCandidate]

Phase 3: 후보 필터링 & 선정

  • 도메인 allowlist/blocklist
  • 해상도 임계값
  • 이미지 유사도 검증 (perceptual hash 재검증)

Phase 4: 아카이빙

  • 선정 URL 다운로드 → R2 업로드 → DB 기록

파일

신규

파일 역할
supabase/migrations/..._add_source_media_originals.sql 스키마
packages/ai-server/src/services/media/original_search/__init__.py 패키지
packages/ai-server/src/services/media/original_search/cropper.py 좌측 인물 크롭
packages/ai-server/src/services/media/original_search/searcher.py ReverseImageSearcher 추상
packages/ai-server/src/services/media/original_search/providers/serpapi_lens.py SerpAPI 구현
packages/ai-server/src/services/media/original_search/selector.py 후보 선정
packages/ai-server/src/services/media/original_search/archiver.py R2 아카이빙
packages/ai-server/src/services/media/original_search/jobs.py ARQ 잡

환경변수

  • SERPAPI_API_KEY
  • ORIGINAL_SEARCH_MIN_WIDTH=800
  • ORIGINAL_SEARCH_ALLOWED_DOMAINS (comma-separated)

검증

  • 샘플 20개 decode 이미지 → 역검색 → 원본 발견율 측정
  • 선정된 원본이 실제로 동일 인물/착장인지 수동 검증 (perceptual hash + 시각 확인)
  • 발견 실패 시 not_found 처리 + 재시도 로직 동작
  • R2 경로 originals/ prefix 분리 확인

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

Labels

Type

No type
No fields configured for issues without a type.

Projects

Status
Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions