feat: deepen pchome momo backfill guardrails
All checks were successful
CD Pipeline / deploy (push) Successful in 1m8s
All checks were successful
CD Pipeline / deploy (push) Successful in 1m8s
This commit is contained in:
@@ -684,6 +684,34 @@ def _targeted_candidate_auto_type(candidate: dict[str, Any]) -> str:
|
||||
return "manual_review"
|
||||
|
||||
|
||||
def _targeted_candidate_needs_review(candidate: dict[str, Any]) -> bool:
|
||||
"""總價自動同步前的最後防線,避免高分但款式待確認的候選進作戰清單。"""
|
||||
if candidate.get("target_hard_veto") is True:
|
||||
return True
|
||||
price_basis = str(candidate.get("target_price_basis") or "").strip()
|
||||
alert_tier = str(candidate.get("target_alert_tier") or "").strip()
|
||||
if price_basis and price_basis != "total_price":
|
||||
return True
|
||||
if alert_tier and alert_tier != "price_alert_exact":
|
||||
return True
|
||||
review_reason_markers = {
|
||||
"manual_review",
|
||||
"identity_review",
|
||||
"unit_price_review",
|
||||
"variant_selection_review",
|
||||
"variant_option_conflict",
|
||||
"variant_descriptor_conflict",
|
||||
"makeup_catalog_selection_gap",
|
||||
"commercial_condition_gap",
|
||||
"count_conflict",
|
||||
"bundle_offer_conflict",
|
||||
"multi_component_conflict",
|
||||
"component_count_conflict",
|
||||
}
|
||||
reasons = {str(reason or "") for reason in (candidate.get("target_match_reasons") or [])}
|
||||
return bool(reasons & review_reason_markers)
|
||||
|
||||
|
||||
def _targeted_candidate_to_external_offer(
|
||||
candidate: dict[str, Any],
|
||||
*,
|
||||
@@ -692,6 +720,8 @@ def _targeted_candidate_to_external_offer(
|
||||
auto_type = _targeted_candidate_auto_type(candidate)
|
||||
if auto_type not in {"total_price", "unit_price"}:
|
||||
return None, "不是可自動使用的候選"
|
||||
if auto_type == "total_price" and _targeted_candidate_needs_review(candidate):
|
||||
return None, "候選仍需人工確認"
|
||||
|
||||
momo_sku = str(candidate.get("product_id") or candidate.get("goodsCode") or candidate.get("id") or "").strip()
|
||||
pchome_product_id = str(candidate.get("target_pchome_product_id") or "").strip()
|
||||
|
||||
@@ -712,6 +712,7 @@ VARIANT_OPTION_COLOR_WORDS = {
|
||||
"棕色",
|
||||
"咖啡色",
|
||||
"灰色",
|
||||
"rose",
|
||||
"白色",
|
||||
"紅色",
|
||||
"粉色",
|
||||
|
||||
@@ -659,16 +659,24 @@ def search_momo_products_for_pchome_products(
|
||||
continue
|
||||
hard_veto = bool(getattr(diagnostics, "hard_veto", False))
|
||||
comparison_mode = getattr(diagnostics, "comparison_mode", "exact_identity")
|
||||
diagnostic_price_basis = str(getattr(diagnostics, "price_basis", "") or "")
|
||||
diagnostic_alert_tier = str(getattr(diagnostics, "alert_tier", "") or "")
|
||||
diagnostic_match_type = str(getattr(diagnostics, "match_type", "") or "")
|
||||
unit_price_comparison = {}
|
||||
auto_compare_type = "manual_review"
|
||||
price_basis = "none"
|
||||
review_status = "需人工確認"
|
||||
if not hard_veto and comparison_mode == "exact_identity":
|
||||
if (
|
||||
not hard_veto
|
||||
and comparison_mode == "exact_identity"
|
||||
and diagnostic_price_basis == "total_price"
|
||||
and diagnostic_alert_tier == "price_alert_exact"
|
||||
):
|
||||
can_auto_compare = True
|
||||
auto_compare_type = "total_price"
|
||||
price_basis = "total_price"
|
||||
review_status = "可直接比價"
|
||||
elif comparison_mode == "unit_comparable":
|
||||
elif comparison_mode == "unit_comparable" or diagnostic_price_basis == "unit_price":
|
||||
unit_price_comparison = build_unit_price_comparison(
|
||||
momo_name,
|
||||
pchome_name,
|
||||
@@ -713,6 +721,8 @@ def search_momo_products_for_pchome_products(
|
||||
"target_search_term": term,
|
||||
"target_match_reasons": list(getattr(diagnostics, "reasons", ()) or ()),
|
||||
"target_comparison_mode": comparison_mode,
|
||||
"target_match_type": diagnostic_match_type,
|
||||
"target_alert_tier": diagnostic_alert_tier,
|
||||
"target_hard_veto": hard_veto,
|
||||
"can_auto_compare": can_auto_compare,
|
||||
"auto_compare_type": auto_compare_type,
|
||||
|
||||
@@ -4,9 +4,26 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from typing import Any, Callable
|
||||
|
||||
|
||||
def _int_env(name: str, default: int, *, minimum: int, maximum: int) -> int:
|
||||
try:
|
||||
value = int(os.getenv(name, str(default)))
|
||||
except (TypeError, ValueError):
|
||||
value = default
|
||||
return max(minimum, min(value, maximum))
|
||||
|
||||
|
||||
def _float_env(name: str, default: float, *, minimum: float, maximum: float) -> float:
|
||||
try:
|
||||
value = float(os.getenv(name, str(default)))
|
||||
except (TypeError, ValueError):
|
||||
value = default
|
||||
return max(minimum, min(value, maximum))
|
||||
|
||||
|
||||
def candidate_auto_compare_type(candidate: dict[str, Any]) -> str:
|
||||
auto_type = str(candidate.get("auto_compare_type") or "").strip()
|
||||
if auto_type in {"total_price", "unit_price"}:
|
||||
@@ -53,9 +70,24 @@ def _default_search_candidates(targets: list[dict[str, Any]], limit: int):
|
||||
return search_momo_products_for_pchome_products(
|
||||
targets,
|
||||
max_products=limit,
|
||||
limit_per_product=6,
|
||||
max_terms_per_product=4,
|
||||
min_score=0.45,
|
||||
limit_per_product=_int_env(
|
||||
"PCHOME_GROWTH_MOMO_BACKFILL_LIMIT_PER_TERM",
|
||||
8,
|
||||
minimum=3,
|
||||
maximum=12,
|
||||
),
|
||||
max_terms_per_product=_int_env(
|
||||
"PCHOME_GROWTH_MOMO_BACKFILL_MAX_TERMS",
|
||||
8,
|
||||
minimum=3,
|
||||
maximum=10,
|
||||
),
|
||||
min_score=_float_env(
|
||||
"PCHOME_GROWTH_MOMO_BACKFILL_MIN_SCORE",
|
||||
0.45,
|
||||
minimum=0.35,
|
||||
maximum=0.8,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user