- Replace `or 70` fallback with explicit None-check so that
min_match_score=0 ("notify all matches") is no longer silently
coerced to 70
- Add test: 200 OK + sent_ids=[] must not mark matches notified
- Add test: threshold=0 correctly pushes low-score matches
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
47 lines
1.6 KiB
Python
47 lines
1.6 KiB
Python
"""신규 매칭을 agent-office로 push하여 텔레그램 알림을 트리거한다."""
|
|
import os
|
|
import logging
|
|
import requests
|
|
|
|
from .db import get_profile, get_unnotified_matches, mark_matches_notified
|
|
|
|
logger = logging.getLogger("realestate-lab")
|
|
|
|
AGENT_OFFICE_URL = os.getenv("AGENT_OFFICE_URL", "http://agent-office:8000")
|
|
NOTIFY_TIMEOUT_SECONDS = int(os.getenv("REALESTATE_NOTIFY_TIMEOUT", "15"))
|
|
|
|
|
|
def notify_new_matches() -> dict:
|
|
"""프로필의 임계값을 통과한 미알림 매칭을 agent-office로 push한다.
|
|
|
|
응답이 200이고 sent_ids가 비어있지 않으면 해당 IDs의 notified_at을 마킹.
|
|
실패 시 마킹하지 않아 다음 사이클에서 재시도된다.
|
|
"""
|
|
profile = get_profile()
|
|
if not profile:
|
|
return {"sent": 0, "skipped": "no_profile"}
|
|
|
|
if not profile.get("notify_enabled"):
|
|
return {"sent": 0, "skipped": "notify_disabled"}
|
|
|
|
raw_threshold = profile.get("min_match_score")
|
|
threshold = 70 if raw_threshold is None else raw_threshold
|
|
matches = get_unnotified_matches(threshold)
|
|
if not matches:
|
|
return {"sent": 0}
|
|
|
|
url = f"{AGENT_OFFICE_URL}/api/agent-office/realestate/notify"
|
|
try:
|
|
resp = requests.post(url, json={"matches": matches}, timeout=NOTIFY_TIMEOUT_SECONDS)
|
|
resp.raise_for_status()
|
|
body = resp.json()
|
|
except requests.RequestException as e:
|
|
logger.error("agent-office push 실패: %s", e)
|
|
return {"sent": 0, "error": str(e)}
|
|
|
|
sent_ids = body.get("sent_ids") or []
|
|
if sent_ids:
|
|
mark_matches_notified(sent_ids)
|
|
logger.info("알림 송신: %d건", len(sent_ids))
|
|
return body
|