서비스 아키텍처 모듈화 - 100-hours-a-week/5-yeosa-wiki GitHub Wiki

아키텍쳐 다이어그램

아키텍쳐 페이지

https://www.figma.com/design/TmY1jyBfLOWmkFcYLCZ2mm/ongi_ai_architecture?node-id=0-1&t=rX1NiRDuo7z8xzPc-1

1. 아키텍처 구조

app/
├── main.py
├── api/
│   ├── main.py 
│   ├── endpoints/
│   │   ├── album_embedding_router.py     # [앨범 임베딩 요청]
    │   ├── album_duplicate_router.py     # [중복 판별]
│   │   ├── album_quality_router.py       # [이미지 품질 측정(흐린 사진 등)]
│   │   ├── album_category_router.py      # [이미지 분류 요청]
│   │   ├── album_score_router.py         # [하이라이트 점수 측정]
│   │   ├── album_people_router.py    # [인물 클러스터링]
    │   └── style_router.py               # [스타일 변환 요청]
│   └── controllers/
│       ├── album_embedding_controller.py
│       ├── album_duplicate_controller.py
│       ├── album_quality_controller.py
│       ├── album_category_controller.py
│       ├── album_score_controller.py
│       ├── album_people_controller.py
│       └── style_controller.py
├── models/
│   ├── clip_loader.py          # CLIP 모델 로드 및 관리
│   └── face_loader.py          # 얼굴 임베딩 모델 로드
├── core/                                     # 서비스 로직에서 공통적으로 사용되는 기능
│   ├── image_loader.py                       # 이미지 불러오기
│   ├── image_cropper.py                      # 얼굴 crop 전처리
│   ├── cache.py                              # Redis or 메모리 기반 캐싱 유틸
│   ├── similarity.py                         # 벡터 유사도 비교 함수
│   └── text_embedding_loader.py              # 태그/카테고리용 텍스트 임베딩 로더
├── services/
│   ├── album/
│   │   ├── clip/
│   │   │   ├── preprocess.py             # clip용 preprocess
│   │   │   ├── embedding.py              # 이미지 임베딩 추출
│   │   │   ├── duplicate.py              # 중복 사진 판별
│   │   │   ├── quality.py                # 사진 품질 측정
│   │   │   ├── category.py               # 카테고리 분류
│   │   │   ├── score.py                  # 하이라이트 점수 추출
│   │   ├── face_recog/
│   │   │   ├── crop_face.py           # 얼굴 crop 처리
│   │   │   └── embedding.py              # 얼굴 임베딩 생성 
│   │   │   └── people.py             # 인물 클러스터링
│   └── thumbnail/
│       ├── prompt_generator.py      # 프롬프트 생성 역할 (Gemini)
│       └── style_transformer.py     # 스타일 변환 역할 (GPU 호출)
├── schemas/
│   ├── album_schema.py                 # Pydantic: 앨범 생성 요청/응답
│   └── style_schema.py                 # Pydantic: 스타일 변환 요청/응답
├──  utils/                             # 단순한 보조 함수
│   ├── image_converter.py              # base64 <-> PIL 변환 등
│   ├── validation.py                   # url 유효성 검사 / 이미지 형식 검증 등
│   ├── logger.py                       # log 담당
│   └── error_handler.py                # error 처리
│
│ -------------------- 아래는 V2부터 반영 --------------------
│
├── workers/
│   ├── duplicate_worker.py           # 메시지 큐 소비자 (중복 판별)
│   ├── quality_worker.py             # 메시지 큐 소비자 (품질 분석)
│   ├── category_worker.py            # 메시지 큐 소비자 (카테고리 분류)
│   ├── score_worker.py               # 메시지 큐 소비자 (하이라이트 스코어)
│   └── utils.py                      # 공통 로직: 메시지 큐 consume, 로깅 등
├── queues/
│   ├── publisher.py                  # 메시지 큐 발행 로직 (controller → queue)
│   └── consumer_base.py              # 워커가 상속받는 공통 큐 소비자 클래스
│
└── config/
    └── settings.py                   # 환경 변수, 큐 연결 설정, 모델 경로 등
    
---------------------- 아래는 V3부터 반영 ---------------------
 
embedding_service/
├── main.py                       # Entrypoint (FastAPI app)
│
├── endpoints/
│   └── embed_router.py          # /embed, /face-embed 등 엔드포인트 정의
│
├── controllers/
│   └── embed_controller.py      # 요청 처리 → image_loader → embedding 호출
│
├── services/
│   ├── image_loader.py          # 이미지 URL/base64 로딩 및 전처리
│   ├── model_loader/
│   │   ├── clip_loader.py       # CLIP 모델 로딩 및 지연 캐싱
│   │   └── face_recog_loader.py # 얼굴 임베딩 모델 로딩
│   └── embedding/
│       ├── clip_embedder.py     # CLIP 임베딩 실행 로직
│       └── face_embedder.py     # 얼굴 임베딩 실행 로직
│
├── schemas/
│   └── request_schema.py        # 요청 파라미터 검증용 Pydantic 모델
│
├── config/
│   └── settings.py              # 모델 경로, 로깅, 디바이스 설정 등
│
└── utils/
    └── timer.py / logger.py     # 로깅, 추론 시간 측정 등

2. 각 모듈의 책임과 기능

a. api/endpoints/

  • RESTful API 엔드포인트를 정의
  • 책임: 외부와 내부 모듈의 인터페이스
  • 분리 이유: 명확한 API 관리 및 버저닝

b. api/controllers/

  • 요청 검증 후 service 계층에 작업 위임
  • 책임: API 계층과 서비스 계층 간의 중간 조율자 역할
  • 분리 이유: 비즈니스 로직과 API 논리의 관심사 분리

c. models/

  • service를 수행할 모델을 load
  • 책임: 모델 로딩, 디바이스 할당, 모델 버전 관리
  • 분리 이유: 비즈니스 로직을 수행하는 모델 관리의 책임을 분산

d. services/

  • 실제 기능 수행 로직 (이미지 임베딩, 품질 평가 등)
  • album/clip / album/facemodel / thumbnail 로 하위 기능을 도메인별로 나눔
  • 책임: AI 모델 실행, 전처리, 후처리, 비즈니스 로직
  • 분리 이유: 독립적 서비스 기능 확장을 위한 명확한 책임 분리

e. core/

  • 전역적으로 재사용되는 모듈 모음
    • 예: 이미지 로더, 유사도 측정, 캐시, 텍스트 임베딩 로더
  • 책임: 서비스 간 공통 유틸리티
  • 분리 이유: 중복 코드 제거, 공통화, 유지보수성 확보

f. utils/

  • 단순 기능: base64 변환, 유효성 검사, 로깅, 에러 핸들링
  • 책임: 코어나 서비스에 포함될 정도는 아니지만 반복되는 도우미 함수
  • 분리 이유: 기타 로직과 명확히 구분하고 가볍게 유지

g. workers/(V2)

  • 메시지 큐를 통해 전달된 태스크를 소비하고 처리하는 실행 단위
  • 예: 중복 판별 워커, 품질 평가 워커, 하이라이트 스코어 워커, 스타일 변환 워커
  • 책임: 각 태스크별 비동기 연산을 병렬로 수행
  • 분리 이유: 컨트롤러와 서비스 레이어에서 무거운 연산을 분리하고, 메시지 기반 처리 구조 확립

h. queues/(V2)

  • 메시지 큐 발행/구독 및 큐 라우팅 관련 로직 집합
  • 예: publish_duplicate_task(), consume_from_queue(), BaseWorker
  • 책임: Controller나 Worker가 사용할 수 있는 큐 인터페이스 제공
  • 분리 이유: 메시지 큐 의존성을 캡슐화하고, 큐 구현체 변경(Redis → Kafka 등)에 유연하게 대응

i. config/(V2)

  • 환경 변수, 경로, 하이퍼파라미터 등 설정 관리
  • 예: 모델 경로, 디바이스(cpu, cuda), Redis 호스트, 큐 이름, 로깅 레벨
  • 책임: 서비스 전반의 설정을 통합적으로 관리
  • 분리 이유: 코드 내 하드코딩 제거, 설정의 일관성과 변경 용이성 확보

2. 모듈간 인터페이스 설계

a. 데이터 포맷

  • 모든 API는 application/json 기반
  • 요청/응답은 모두 schemas/에 정의된 Pydantic 모델 기반

가. 예시: 이미지 임베딩 요청

POST /api/v1/albums/embeddings
Content-Type: application/json

{
  "images": ["http://server:8000/img1.jpg", "http://server:8000/img2.jpg"]
}
{
  "message": "success",
  "data": null
 }

나. 내부 처리 흐름(V1)

[endpoint]
   ↓
[controller]
   ↓
[services/album/clip/embedding.py]         # CLIP embedding 수행
   ↓
[core/image_loader + core/cache]           # 이미지 로드, embedding 캐시 저장
   ↓
[services/album/clip/*.py]                 # 중복 판별, 점수 계산, 품질 측정, 카테고리 분류
[services/album/face_recog/*.py]           # 얼굴 crop 및 클러스터링
[services/thumbnail/style_transformer.py]  # 스타일 변환
  • 모든 내부 호출은 동기 함수 기반, 향후 비동기 리팩토링 여지 확보

다. 내부 처리 흐름 (v2)

[endpoint]
   ↓
[controller]
   ↓
[core/cache]                  # 캐시에 embedding 있는지 확인
   ↓
[services/album/clip/embedding.py]   # embedding 직접 수행
   ↓
[core/cache]                  # embedding 저장
   ↓
[queues/publisher]            # 중복 판별, 점수 계산 등 작업을 메시지 큐에 발행
   ↓
[message queue]
   ↓
[workers/*_worker.py]         # 큐 소비 → 태스크 처리
   ↓
[core/cache]                  # embedding 불러오기
   ↓
[services/album/clip/*.py]             # duplicate.py, score.py, category.py, quality.py
[services/album/face_recog/*.py]       # people.py (얼굴 클러스터링)
[services/thumbnail/style_transformer.py]  # 스타일 변환

라. v1과 v2의 주요 차이점

항목 v1 v2
태스크 처리 방식 동기적으로 한 번에 수행 embedding 이후는 비동기 큐 처리
워커 사용 여부 없음 있음 (duplicate, score 등 분리 처리)
embedding 위치 services 내부 여전히 내부에 있음 (단, 큐와 분리 구조로 정리됨)
embedding 재사용 암묵적 재사용 명시적으로 캐시에 저장하고 조회

3. 모듈화의 기대 효과 및 장점

항목 기대 효과
개발 효율성 팀원이 각 서비스 기능을 독립적으로 개발 및 테스트 가능
유지보수 용이성 특정 기능 변경 시 관련 모듈만 수정하면 됨 (예: quality.py만 수정)
확장성 확보 새로운 기능이나 모델 추가 시 기존 코드에 영향 없음
재사용성 증가 core/, utils/ 내 기능은 모든 서비스에서 공통 활용 가능
CLIP embedding 재사용
배포 최적화 향후 병목현상 등 발생 시, AI 서비스별로 마이크로서비스 구조로 이관 가능

4. 팀 서비스 시나리오와의 적합성 근거

a. 시나리오 기반 예시 1: 모델 교체 혹은 추가

  • 예: 현재 CLIP 모델 외에 Mistral 기반 텍스트 태깅 모델 추가
  • services/album/clip/과 병행하여 services/album/mistral/ 디렉토리만 추가하면 됨
  • ➜ API/Controller/Core는 변경할 필요 없음

b. 시나리오 기반 예시 2: 품질 평가 기준 변경

  • 흐림 뿐만 아니라 밝기나 노이즈 기준 추가 요청 발생
  • quality.py 내부의 품질 판단 함수만 변경하면 전체 시스템 반영 완료
  • ➜ API는 그대로 유지되므로 사용자/프론트엔드는 영향 없음

c. 시나리오 기반 예시 3: 하이라이트 점수 개선 로직

  • 새 점수 기준을 A/B 테스트하고 싶은 경우
  • score.py 내부 로직만 분기처리하면 테스트 가능

5. 흐름 요약

a. services/album/

가. 이미지 임베딩 요청 (POST /api/v1/albums/embeddings)

  • album_embedding_router.pyalbum_embedding_controller.py

    embedding.py

  • 임베딩해서 캐시에 저장(image_loader.pypreprocess.pyembedding.pycache.py)

  • 클라이언트에 임베딩 성공했음을 알림. 임베딩 성공 후, 캐싱된 임베딩으로태깅&중복 판별&인물 클러스터링이 비동기로 진행됨.

나. 중복/저품질 이미지 판별 요청 (POST /api/v1/albums/duplicates, POST /api/v1/albums/quality)

  • album_duplicate_router.pyalbum_duplicate_controller.py

    duplicate.pycache.pysimilarity.py

  • album_quality_router.pyalbum_quality_controller.py

    quality.pycache.pyquality.py

  • 유사도 기반으로 중복 이미지 / 저품질(흐린) 이미지 그룹화

다. 이미지 분류/하이라이트 점수/인물 클러스터링 요청 (POST /api/v1/albums/categories, POST /api/v1/albums/scores, POST /api/v1/albums/people)

  • album_category_router.pyalbum_category_controller.py

    category.pycache.pytext_embedding_loader.pysimilarity.py

  • album_score_router.pyalbum_score_controller.pyscore.pycache.pyscore.py

  • album_people_router.pyalbum_people_controller.py

    people.pyfacemodel/embedding.pycrop_face.pypeople.py

b. services/thumbnail/

가. 스타일 변환 요청 (POST /api/v1/style)

  • style_router.pystyle_controller.py

    image_downloader.py (이미지 다운로드)

    gemini_service.py (이미지 기반 프롬프트 생성)

    image_converter.py (PIL → base64 변환)

    gpu_server_service.py (base64 + 프롬프트 전달)

    s3_uploader.py (결과 이미지 S3 업로드 후 URL 반환)