收斂 PChome gate pass 變體風險
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s

This commit is contained in:
OoO
2026-05-25 23:08:31 +08:00
parent 64a39a89b3
commit f2aa81815e
5 changed files with 151 additions and 1 deletions

View File

@@ -2042,10 +2042,30 @@ def score_marketplace_match(
relove_private_cleanser_variant_gap = _has_relove_private_cleanser_variant_gap(left, right)
if relove_private_cleanser_variant_gap:
reasons.append("relove_private_cleanser_variant_gap")
makeup_catalog_selection_gap = _has_makeup_catalog_selection_gap(left, right)
if makeup_catalog_selection_gap:
reasons.append("makeup_catalog_selection_gap")
loreal_serum_variant_gap = _has_loreal_serum_variant_gap(left, right)
if loreal_serum_variant_gap:
reasons.append("loreal_serum_variant_gap")
sebamed_shampoo_variant_catalog_gap = _has_sebamed_shampoo_variant_catalog_gap(left, right)
if sebamed_shampoo_variant_catalog_gap:
reasons.append("sebamed_shampoo_variant_catalog_gap")
schick_2in1_model_gap = _has_schick_2in1_model_gap(left, right)
if schick_2in1_model_gap:
reasons.append("schick_2in1_model_gap")
taicend_protection_form_gap = _has_taicend_protection_form_gap(left, right)
if taicend_protection_form_gap:
reasons.append("taicend_protection_form_gap")
variant_selection_review = (
_has_named_variant_selection_review(left, right, shared_anchor)
or commercial_condition_gap
or relove_private_cleanser_variant_gap
or makeup_catalog_selection_gap
or loreal_serum_variant_gap
or sebamed_shampoo_variant_catalog_gap
or schick_2in1_model_gap
or taicend_protection_form_gap
)
if variant_selection_review:
reasons.append("variant_selection_review")
@@ -3375,6 +3395,93 @@ def _has_relove_private_cleanser_variant_gap(left: ProductIdentity, right: Produ
return left_brightening != right_brightening
def _has_makeup_catalog_selection_gap(left: ProductIdentity, right: ProductIdentity) -> bool:
pair_text = f"{left.searchable_name} {right.searchable_name}"
sensitive_terms = (
"遮瑕蜜",
"遮瑕",
"粉底",
"粉霜",
"氣墊",
"蜜粉",
"腮紅",
"眼線",
"眉筆",
"染眉膏",
"唇膏",
"唇釉",
"唇蜜",
)
if not any(term in pair_text for term in sensitive_terms):
return False
if not (_is_catalog_or_delimited_variant_listing(left) or _is_catalog_or_delimited_variant_listing(right)):
return False
left_shades = _makeup_shade_tokens(left)
right_shades = _makeup_shade_tokens(right)
if left_shades and right_shades and _variant_options_overlap(left_shades, right_shades):
return False
return True
def _has_loreal_serum_variant_gap(left: ProductIdentity, right: ProductIdentity) -> bool:
pair_text = f"{left.searchable_name} {right.searchable_name}"
if not ({"loreal", "巴黎萊雅"} & (left.brand_tokens | right.brand_tokens)):
return False
if "玻尿酸瞬效保濕" not in pair_text:
return False
variant_terms = ("啵啵精華水", "液態紫熨斗", "水光精華", "修護晶露", "保濕水光")
left_terms = {term for term in variant_terms if term in left.searchable_name}
right_terms = {term for term in variant_terms if term in right.searchable_name}
if not (left_terms or right_terms):
return False
return left_terms != right_terms or _is_catalog_or_delimited_variant_listing(left) != _is_catalog_or_delimited_variant_listing(right)
def _has_sebamed_shampoo_variant_catalog_gap(left: ProductIdentity, right: ProductIdentity) -> bool:
if not ({"sebamed", "施巴"} & (left.brand_tokens | right.brand_tokens)):
return False
if "洗髮乳" not in left.searchable_name or "洗髮乳" not in right.searchable_name:
return False
variant_terms = ("溫和", "油性抗屑", "抗屑", "乾性", "敏感")
left_terms = {term for term in variant_terms if term in left.searchable_name}
right_terms = {term for term in variant_terms if term in right.searchable_name}
if _is_catalog_or_delimited_variant_listing(left) != _is_catalog_or_delimited_variant_listing(right):
return True
return bool(left_terms or right_terms) and left_terms != right_terms
def _has_schick_2in1_model_gap(left: ProductIdentity, right: ProductIdentity) -> bool:
if not ({"schick", "舒適牌"} & (left.brand_tokens & right.brand_tokens)):
return False
pair_text = f"{left.searchable_name} {right.searchable_name}"
if "舒綺" not in pair_text or "美型刀" not in pair_text:
return False
left_2in1 = bool(re.search(r"2\s*(?:-?in-?|合)?\s*1", left.searchable_name, re.I))
right_2in1 = bool(re.search(r"2\s*(?:-?in-?|合)?\s*1", right.searchable_name, re.I))
return left_2in1 != right_2in1
def _has_taicend_protection_form_gap(left: ProductIdentity, right: ProductIdentity) -> bool:
if not ({"taicend", "泰陞"} & (left.brand_tokens & right.brand_tokens)):
return False
pair_text = f"{left.searchable_name} {right.searchable_name}"
if "保護膜" not in pair_text and "保護噴霧" not in pair_text and "液態皮膚保護膜" not in pair_text:
return False
if "屁屁噴" in left.searchable_name and "屁屁噴" in right.searchable_name:
return False
left_terms = {
term
for term in ("寶貝液體保護膜", "液態皮膚保護膜", "皮膚保護噴霧", "保護噴霧")
if term in left.searchable_name
}
right_terms = {
term
for term in ("寶貝液體保護膜", "液態皮膚保護膜", "皮膚保護噴霧", "保護噴霧")
if term in right.searchable_name
}
return bool(left_terms or right_terms) and left_terms != right_terms
def _has_catalog_specific_variant_selection_gap(left: ProductIdentity, right: ProductIdentity) -> bool:
pair_text = f"{left.searchable_name} {right.searchable_name}"
if not any(