"""큐레이션 직전 호출 — review 1건 + 추세 3건 → 컨텍스트 dict.""" import json from typing import Optional, Dict, Any from .. import service_proxy def _detect_bias(reviews: list) -> str: """3주↑ 같은 방향 패턴 편향이 유지되면 한 줄로.""" deltas = [r.get("pattern_delta") or "" for r in reviews if r.get("pattern_delta")] if len(deltas) < 2: return "" # 단순 휴리스틱 — 같은 키워드("저번호" 등)가 2회 이상이면 지속 편향 keywords = ["저번호", "고번호", "합계", "홀짝"] persistent = [] for kw in keywords: cnt = sum(1 for d in deltas if kw in d) if cnt >= max(2, len(deltas) - 1): persistent.append(kw) return " · ".join(persistent) async def build_retrospective(target_draw_no: int) -> Optional[Dict[str, Any]]: """target_draw_no(이번 주) 직전 회차의 review + 그 앞 3회 추세.""" last = await service_proxy.lotto_review_by_draw(target_draw_no - 1) if not last: return None history = await service_proxy.lotto_reviews_history(limit=4) # history 는 desc 정렬 → last 와 그 이전 3건 분리 others = [r for r in history if r["draw_no"] < target_draw_no - 1][:3] series = [last] + others cur_avgs = [r["curator_avg_match"] for r in series if r.get("curator_avg_match") is not None] usr_avgs = [r["user_avg_match"] for r in series if r.get("user_avg_match") is not None] return { "last_draw": { "draw_no": last["draw_no"], "curator_avg": last.get("curator_avg_match"), "curator_best_tier": last.get("curator_best_tier"), "user_avg": last.get("user_avg_match"), "user_5plus": last.get("user_5plus_prizes"), "pattern_delta": last.get("pattern_delta") or "", }, "trend_4w": { "curator_avg_4w": round(sum(cur_avgs) / len(cur_avgs), 2) if cur_avgs else None, "user_avg_4w": round(sum(usr_avgs) / len(usr_avgs), 2) if usr_avgs else None, "user_persistent_bias": _detect_bias(series), }, }