diff --git a/config.py b/config.py index 16d6749..8713fa2 100644 --- a/config.py +++ b/config.py @@ -325,7 +325,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '') # ========================================== # 系統版本與路徑 # ========================================== -SYSTEM_VERSION = "V10.393" +SYSTEM_VERSION = "V10.394" LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log') public_url = PUBLIC_URL # 用於模板顯示 diff --git a/docs/memory/history_logs.md b/docs/memory/history_logs.md index f80ab36..6436852 100644 --- a/docs/memory/history_logs.md +++ b/docs/memory/history_logs.md @@ -13,6 +13,7 @@ ## 📅 詳細更新日誌 (考古存檔) ### 2026-05-21:瀏覽器測試守門與 PChome 熱路徑優化 +- **V10.394 多色 catalog / 入門組防錯配**: marketplace matcher 補「琥珀橙 / 干邑棕 / 賽車綠」等車用香氛色款詞,當 MOMO 是多色/多款 catalog listing、PChome 是單一色款候選時會保留 `variant_option_conflict` hard veto;同時把 `入門組` 納入套組詞,避免理膚寶水抗敏入門組被拿去跟單瓶乳液做總價比價。 - **V10.393 組合包 `+` 判定修正與 catalog 補強**: marketplace matcher 的組合包件數判定會先排除 `SPF50+`、`PA++++` 等防曬係數加號,以及 `NTT80+AL414` 這類純型號碼串,避免把防曬品與 OPI 套組的規格/型號加號誤判成多一個商品組件;CeraVe 三件組 vs 兩件組仍維持 `multi_component_count_conflict` hard veto。同版收緊品牌 alias 判定,避免只有品牌名就觸發商品線加成,並補 Baan 貝恩嬰兒修護唇膏「原味/草莓」catalog listing 放行。 - **V10.392 組合包件數防錯配**: marketplace matcher 新增 `multi_component_count_conflict`,當 MOMO 與 PChome 都是 `+`/`+` 組合包但組件數不同時直接進 `not_comparable`,避免三件組被拿去跟兩件組做總價告警;同步把該原因加入 evidence flags,讓告警與審核畫面可以清楚顯示「組合包件數不同」。 - **V10.391 多款任選 catalog listing 防錯配**: marketplace matcher 新增 `catalog_variant_listing_alignment`,當 MOMO/PChome 雙方都是多款/多色/多香味任選 listing,且商品線、規格與類型一致時,可放行香氛擴香罐、香氛蠟燭等 catalog 型同款;同時把 Relove 菸鹼醯胺 vs 胺基酸私密清潔凝露列為變體衝突,並讓 competitor feeder 不再只因 `strong_exact_spec_match` 就把低分候選視為 recoverable,避免只同規格但品線不同的商品回寫正式比價。 diff --git a/services/marketplace_product_matcher.py b/services/marketplace_product_matcher.py index a368e4b..77e1e5c 100644 --- a/services/marketplace_product_matcher.py +++ b/services/marketplace_product_matcher.py @@ -489,6 +489,9 @@ VARIANT_OPTION_COLOR_WORDS = { "清甜柚香", "杏仁牛奶", "完熟白桃", + "琥珀橙", + "干邑棕", + "賽車綠", "原味", "草莓", "蔓越莓", @@ -647,6 +650,7 @@ BUNDLE_OFFER_PHRASES = ( "特惠組", "優惠組", "優惠套組", + "入門組", "禮盒組", "加大組", "加量組", @@ -2591,6 +2595,14 @@ def _explicit_variant_option_tokens(identity: ProductIdentity) -> set[str]: return options +def _has_variant_option_selection_gap(identity: ProductIdentity, options: set[str]) -> bool: + named_options = {option for option in options if not option.isdigit()} + if len(named_options) < 2: + return False + text = identity.searchable_name + return _is_multi_variant_catalog_listing(identity) or bool(re.search(r"[//、,,]", text)) + + def _has_explicit_variant_option_conflict( left: ProductIdentity, right: ProductIdentity, @@ -2602,7 +2614,17 @@ def _has_explicit_variant_option_conflict( right_options = _explicit_variant_option_tokens(right) if not left_options or not right_options: return False + if left_options == right_options: + return False if left_options & right_options: + if ( + len(left_options) > len(right_options) + and _has_variant_option_selection_gap(left, left_options) + ) or ( + len(right_options) > len(left_options) + and _has_variant_option_selection_gap(right, right_options) + ): + return True return False for left_option in left_options: for right_option in right_options: diff --git a/tests/test_marketplace_product_matcher.py b/tests/test_marketplace_product_matcher.py index 0c83f60..805f73b 100644 --- a/tests/test_marketplace_product_matcher.py +++ b/tests/test_marketplace_product_matcher.py @@ -876,6 +876,32 @@ def test_marketplace_matcher_promotes_baan_lip_catalog_with_same_options(): assert "catalog_variant_listing_alignment_baan_lip" in diagnostics.reasons +def test_marketplace_matcher_rejects_multi_color_catalog_against_single_color_candidate(): + from services.marketplace_product_matcher import score_marketplace_match + + diagnostics = score_marketplace_match( + "【L‘Original London 洛瑞歐】官方直營 皇家小羊皮車用香氛禮盒 琥珀橙/干邑棕/賽車綠 生日禮物送", + "英國L’Original精品小羊皮車用香氛禮盒-干邑棕(平行輸入)", + ) + + assert diagnostics.score < 0.76 + assert diagnostics.hard_veto is True + assert "variant_option_conflict" in diagnostics.reasons + + +def test_marketplace_matcher_rejects_starter_set_against_single_lotion(): + from services.marketplace_product_matcher import score_marketplace_match + + diagnostics = score_marketplace_match( + "【理膚寶水】安心抗敏入門組★多容安舒緩濕潤乳液_A(安心乳液/敏感肌保濕)", + "理膚寶水 多容安舒緩濕潤乳液 40ml", + ) + + assert diagnostics.score < 0.76 + assert diagnostics.hard_veto is True + assert "bundle_offer_conflict" in diagnostics.reasons + + def test_marketplace_matcher_rejects_refill_core_vs_case_only_pack(): from services.marketplace_product_matcher import score_marketplace_match