"""잡 핸들러 — job_type 별 처리. 현재는 SEARCH(검색)만. 검색 핸들러: 소스 어댑터로 검색 → 코어 파이프라인(필터·이상치·top-N 최저가) → 결과. AI 유사도 판정은 파이프라인 슬롯에 키 준비 시 결합한다. """ from common.enums import JobType from services.search.contract import SearchAdapter from services.search.util import parse_price from services.pipeline.core import run_price_pipeline def build_search_handler(adapters: dict[str, SearchAdapter], default_source: str = "coupang", limit: int = 40, top_n: int = 5): """검색 핸들러 생성. adapters = {source: SearchAdapter}.""" async def handler(job: dict) -> dict: if job["job_type"] != JobType.SEARCH.value: raise ValueError(f"unsupported job_type: {job['job_type']}") payload = job.get("payload") or {} query = (payload.get("product_name") or "").strip() if not query: raise ValueError("empty product_name") adapter = adapters.get(default_source) if adapter is None: raise ValueError(f"no adapter for source: {default_source}") products = await adapter.search(query, limit=limit) # 요청 현재가(있으면)를 가격 밴드 기준으로 사용 → 엉뚱한 저가/고가 targeted 컷 base_price = parse_price(payload.get("price")) result = run_price_pipeline(products, base_price=base_price, top_n=top_n) result["source"] = adapter.source result["query"] = query return result return handler