# rag-demo/scripts/build_index_qa.py """ 벡터 DB 인덱스 구축 (FAISS 전용) Qdrant 모드에서는 ingest_qa.py에서 실시간 인덱싱되므로 이 스크립트는 skip됩니다. """ import os import sys from pathlib import Path VECTOR_STORE = os.getenv("VECTOR_STORE", "faiss").lower() if VECTOR_STORE == "qdrant": print("✅ Qdrant 모드: 인덱스 빌드 불필요 (실시간 인덱싱)") sys.exit(0) # FAISS 모드: 기존 벡터 파일 → 인덱스 생성 import json, pickle import numpy as np from vector_store import FAISSStore # ─────────────────────────────────────────── SRC = Path("/app/data/qa_vecs.jsonl") DATA_DIR = Path("/app/data") INDEX_FILE = DATA_DIR / "qa.index" META_FILE = DATA_DIR / "qa_meta.pkl" # ────────────────────────────────────────────── # ✅ 스킵 로직: 이미 인덱스가 생성되었는지 확인 # ────────────────────────────────────────────── def should_skip_indexing(): """인덱싱 작업을 스킵해야 하는지 판단""" if not INDEX_FILE.exists() or not META_FILE.exists(): return False # qa_vecs.jsonl과 qa_meta.pkl의 라인 수 비교 try: with open(SRC, 'r', encoding='utf-8') as f: vec_lines = sum(1 for line in f if line.strip()) with open(META_FILE, 'rb') as f: import pickle metas = pickle.load(f) meta_count = len(metas) if vec_lines == meta_count: print(f"[Index] ✅ 인덱스 이미 생성됨 (vectors: {vec_lines}개, metadata: {meta_count}개)") print(f"[Index] ⏩ 스킵합니다. 재인덱싱이 필요하면 'rm {INDEX_FILE} {META_FILE}'을 실행하세요.") return True else: print(f"[Index] ⚠️ 개수 불일치 (vectors: {vec_lines}개, metadata: {meta_count}개) → 재인덱싱") return False except Exception as e: print(f"[Index] ⚠️ 스킵 체크 실패: {e} → 인덱싱 진행") return False # 벡터 파일이 없으면 ingest_qa.py가 이미 인덱싱 완료 if not SRC.exists(): print("[Index] ✅ qa_vecs.jsonl 없음: ingest_qa.py에서 이미 인덱싱 완료") sys.exit(0) if should_skip_indexing(): print("[Index] 🎉 인덱싱 작업 완료 (스킵)") sys.exit(0) # 기존 JSONL 형식 벡터 파일 읽기 (하위 호환) vecs, metas = [], [] with SRC.open(encoding="utf-8") as fin: for line in fin: obj = json.loads(line) vecs.append(obj["vec"]) metas.append(obj["meta"]) arr = np.asarray(vecs, dtype="float32") # FAISS 스토어에 추가 및 저장 store = FAISSStore() store.add_vectors(arr, metas) store.save(str(DATA_DIR)) print(f"✅ FAISS 인덱스 저장: {DATA_DIR}/qa.index (vectors={arr.shape[0]}, dim={arr.shape[1]})")