Runbook

Landmark Assistant 데모 앱 운영 가이드

팀원 PC에서 Sprint 1 Streamlit demo app을 실행하고, 같은 Wi-Fi의 스마트폰 브라우저로 시연하기 위한 legacy 절차다. 최신 Sprint 2 Flutter/온디바이스 앱 artifact 구조는 Model Serving Contract를 따른다.

현재 문서 상태

이 문서는 Sprint 1 demo app 재현용이다. best.pt 직접 실행은 개발/비교용으로 남긴다. Sprint 1 시연 기본값은 mobile_artifacts_int8/를 사용하는 python run.py --int8다. 최신 Sprint 2 앱 전달용 모델은 mobile_artifacts/fp16의 image/text encoder 분리 bundle이다.

Sprint 2 앱 artifact 기준

새 앱 구현에서는 landmark_encoder.onnx 하나를 찾지 않는다. manifest.json을 읽어 image encoder와 text encoder 파일명을 각각 확인한다.

mobile_artifacts/fp16/
  mobileclip2_s3_server_full_ce_hardneg_image_encoder_fp16_mixed.onnx
  mobileclip2_s3_server_full_ce_hardneg_image_encoder_fp16_mixed.onnx.data
  mobileclip2_s3_server_full_ce_hardneg_text_encoder_fp16_mixed.onnx
  mobileclip2_s3_server_full_ce_hardneg_text_encoder_fp16_mixed.onnx.data
  manifest.json
  preprocessing.json
  tokenizer.json
  prototype_index.json
  classes.json
  labels_master.json
  config.yaml

이미지 검색은 image -> image encoder -> embedding -> prototype_index 흐름이고, 텍스트 검색은 query -> tokenizer -> text encoder -> text embedding -> text catalog/index 흐름이다. 상세 화면 정보는 모델 artifact가 아니라 앱의 landmark catalog 또는 DB에서 조회한다.

데모 앱 구조 한눈에 보기

Sprint 1 데모 앱은 Streamlit UI, 모델/검색 코드, 정적 자산, 모바일 artifact를 분리해서 운용한다. GitHub repo에는 실행 코드와 작은 JSON 자산이 들어가고, 큰 모델 파일은 별도 전달한다.

landmark-demo-app/
  run.py                         # Streamlit launcher
  config.toml                    # PyTorch best.pt 실행 설정
  config.onnx.toml               # FP32 ONNX 실행 설정
  config.int8.toml               # Sprint 1 기본: dynamic INT8 ONNX 실행 설정
  pyproject.toml                 # pip install -e . / .[onnx] 의존성
  best.pt                        # PyTorch checkpoint, git에 올리지 않음
  mobile_artifacts_int8/         # Sprint 1 데모용 INT8 ONNX artifact, git에 올리지 않음
  assets/
    landmark_info.json           # 상세 페이지 metadata
    landmark_text_catalog_v2.json # 사람이 관리하는 한/영 검색 표현 사전
    landmark_text_index.json      # text catalog를 embedding으로 변환한 검색 인덱스
    prototype_index.json          # class별 image prototype
    hero_images/                  # 상세 페이지 대표 이미지
  src/landmark_demo/
    app.py                       # Streamlit 화면과 사용자 interaction
    config.py                    # TOML config loader
    data.py                      # assets 로딩과 정합성 검증
    inference.py                 # PyTorch/ONNX image, text encoder wrapper
    model.py                     # MobileCLIP2 checkpoint wrapper
    search.py                    # image/text search, confidence policy
    logging_util.py              # JSONL debug log
  scripts/
    build_assets.py              # best.pt + Dataset -> prototype/text/hero assets
    export_mobile_onnx.py        # best.pt -> ONNX artifact
    benchmark_mobile_artifact.py # PyTorch vs ONNX 비교
  tests/
    fixtures/                    # demo regression 입력과 기대 결과

실행 모드

명령 사용 config 모델 경로 용도
python run.py config.toml best.pt 개발/비교용 PyTorch 원본 실행.
python run.py --onnx config.onnx.toml mobile_artifacts/ FP32 ONNX export 결과 확인.
python run.py --int8 config.int8.toml mobile_artifacts_int8/ Sprint 1 demo app 재현 경로.

run.py는 선택된 config를 LANDMARK_DEMO_CONFIG 환경변수에 넣고 streamlit run src/landmark_demo/app.py0.0.0.0:8501로 실행한다. 그래서 같은 Wi-Fi의 스마트폰에서도 http://<노트북_IP>:8501로 접근할 수 있다.

런타임 흐름

사용자 입력
  ├─ 이미지 업로드
  │   └─ app.py
  │      └─ inference.py: ONNX image encoder로 image embedding 생성
  │         └─ search.py: prototype_index와 cosine 비교
  │            └─ confidence policy: matched / ambiguous / out_of_scope / low_quality
  │               └─ app.py: Top-3, 안내 문구, 상세 페이지 표시
  └─ 자연어 검색
      └─ app.py
         └─ inference.py: text encoder 사용 가능 시 text embedding 생성
            └─ search.py: landmark_text_index embedding + keyword 문자열 보정
               └─ confidence policy 적용

이미지 검색은 prototype_index.json를 직접 사용하고, 자연어 검색은 landmark_text_index.json와 keyword matching을 함께 사용한다. landmark_text_catalog_v2.json는 사람이 편집하는 원본 사전이고, 앱 실행 시 직접 비교되는 것은 이 사전에서 생성된 landmark_text_index.json다.

주요 모듈 책임

파일 책임 문제 발생 시 먼저 볼 것
app.py Streamlit 화면, 탭 전환, 업로드, 결과 카드, 상세 페이지. 화면이 안 뜨거나 UI flow가 이상할 때.
config.py config.toml 계열 파일을 읽어 경로, threshold, backend를 결정. 다른 artifact/config로 실행해야 할 때.
data.py landmark_info, prototype_index, landmark_text_index 로딩과 정합성 확인. 자산 누락, landmark_id 불일치, 상세정보 오류.
inference.py 이미지 전처리, PyTorch/ONNX encoder 호출, text encoder wrapper. 모델 로딩, ONNX Runtime, latency, embedding 생성 오류.
search.py cosine similarity, keyword score, fusion score, threshold/margin decision. 검색 결과 순위, ambiguous/OOS 판정, 점수 정책 조정.
logging_util.py 검색 입력, Top-3, decision, reason code를 JSONL로 저장. 시연 후 실패 사례 분석.

Sprint 1 데모앱 파일 배치

landmark-demo-app/
  run.py
  config.int8.toml
  assets/
  src/
  mobile_artifacts_int8/
    landmark_encoder.onnx
    landmark_encoder.onnx.data
    preprocessing.json
    prototype_index.json
    labels_master.json
    manifest.json
    quantization_regression_report.json

이 구조는 Sprint 1 demo app 전용이다. 압축을 풀었을 때 mobile_artifacts_int8/mobile_artifacts_int8/...처럼 폴더가 두 겹이면 안 된다. landmark_encoder.onnx가 바로 mobile_artifacts_int8/ 안에 있어야 한다. Sprint 2 앱에서는 이 파일명이 아니라 manifest.json의 image/text encoder 항목을 따른다.

빠른 시작

git clone https://github.com/HyunKN/landmark-demo-app.git
cd landmark-demo-app
pip install -e ".[onnx]"

# mobile_artifacts_int8 폴더를 repo 루트에 둔 뒤
python run.py --int8

브라우저에서 http://localhost:8501을 연다.

스마트폰 브라우저 시연

  1. 노트북과 스마트폰을 같은 Wi-Fi에 연결한다.
  2. 노트북에서 python run.py --int8를 실행한다.
  3. Windows 방화벽이 뜨면 Python 또는 8501 포트를 허용한다.
  4. 노트북 IP를 확인한다: ipconfig의 IPv4 주소.
  5. 스마트폰 브라우저에서 http://<노트북_IP>:8501로 접속한다.

이 방식은 “스마트폰 화면에서 앱처럼 사용”을 보여주지만, 추론은 노트북에서 수행한다. 실제 스마트폰 NPU latency는 Qualcomm AI Hub 측정값을 별도 근거로 제시한다.

기능

입력 동작
이미지 JPEG/PNG/WEBP, 10MB 이하 ONNX image encoder → prototype cosine → Top-3 또는 confidence policy 안내.
자연어 한국어/영어 검색어 Sprint 1 demo app은 text index와 keyword 기반 검색. Sprint 2 앱은 별도 text encoder ONNX를 사용한다.

2026-05-17 검증 이후 이름 검색 탭은 제거했다. Sprint 1 시연 흐름을 이미지 검색과 자연어 검색으로 단순화하고, 장소 이름 검색은 자연어 탭의 keyword/catalog 검색에 흡수한다.

신뢰도 상태

상태 화면 의미 로그에서 볼 것
matched 가장 가능성이 높은 랜드마크와 Top-3 후보를 표시. top1_score, margin, reason_codes
ambiguous 한 곳으로 확정하지 않고 가까운 후보를 함께 표시. 낮은 margin, 중간 top1 score.
out_of_scope 지원 범위 밖으로 안내. 후보는 참고용으로만 노출 가능. top1 below reject, keyword miss, screenshot-like 등.
low_quality 재촬영 또는 더 선명한 사진 요청. blur/dark/min-side 품질 사유.

개발/비교용 명령

# PyTorch 원본 실행: best.pt 필요
python run.py

# FP32 ONNX 실행: mobile_artifacts/ 필요
python run.py --onnx

# 팀원 시연 기본값: mobile_artifacts_int8/ 필요
python run.py --int8

주의

Sprint 1의 mobile_artifacts_int8.zip과 Sprint 2의 mobileclip2_s3_fp16_mixed_artifacts.zip은 용량 때문에 GitHub repo에 올리지 않는다. 팀원에게 압축 파일로 따로 전달한다. GitHub에는 실행 코드와 설정만 올라간다.