diff --git a/config.py b/config.py index c5ce7d2..3cbae68 100644 --- a/config.py +++ b/config.py @@ -325,7 +325,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '') # ========================================== # 系統版本與路徑 # ========================================== -SYSTEM_VERSION = "V10.400" +SYSTEM_VERSION = "V10.401" 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 29db29d..402f6ae 100644 --- a/docs/memory/history_logs.md +++ b/docs/memory/history_logs.md @@ -13,6 +13,7 @@ ## 📅 詳細更新日誌 (考古存檔) ### 2026-05-24:PChome 近門檻身份回收第二輪 +- **V10.401 focused identity 邊界整理**: 將 Laundrin TOKYO 車用夾式消臭芳香劑判定抽成 `_has_laundrin_tokyo_car_freshener_alignment()`,並在 variant descriptor guard 中豁免同一條強身份線,避免 TOKYO / 車用 / 芳香劑語序差異造成誤擋。Yuskin 經典乳霜 30g 6 入組改用 `_has_exact_count_alignment()` 判斷包數,保留 6入 vs 6盒這類同數量但不同容器字詞的人工覆核路徑。 - **V10.400 氣墊粉餅補充蕊包數正規化**: marketplace matcher 針對氣墊粉餅新增保守的 `cushion_refill_pack_alignment`,只在一側明確為 `一盒兩蕊 / 2蕊`、另一側為單規格 `15g x2` 這類乘數包裝時,解除 `multi_component_conflict` 並進 `identity_review`。CLIO 羽緻無限緞光氣墊粉餅「一盒兩蕊」可被同款覆核;`2盒4蕊` 對 `15g x2` 仍維持 hard veto。同版補香氛蠟燭、TOKYO 車用消臭芳香劑、融蠟燈與有機護膚油 search identity anchors。離線 audit 759 筆 accepted 從 753 提升到 754,剩餘 5 筆 fresh veto 皆為應擋的套組/品類差異。 - **V10.399 多香味 catalog 價格告警降級**: marketplace matcher 新增 `variant_selection_review`,當一側是無明確選項的商品線、另一側列出多個具名香味/款式選項時,允許同款身份回收但只進 `identity_review`,不直接進 `price_alert_exact`。首個正式案例是 HH 女性私密衣物抗菌手洗精 200ml 對 PChome 白麝香/清新花園/寶貝粉香多香味 listing;此規則避免把多香味 catalog 價格誤當單一 variant 精準比價。 - **V10.398 true low confidence 保守回收**: marketplace matcher 針對正式前段 `true_low_confidence` 補一輪 focused exact identity lines,讓 Baan 嬰兒修護唇膏、植村秀 3D 極細防水眼線膠筆、YSL 恆久完美透膚煙染腮紅、HH 私密植萃美白緊緻凝露、Lab52 學習刷牙漱口水、Benefit 經典菲菲染唇液、Herb24 晨霧純精油擴香儀、Pavaruni 40 香味 10ml 精油與 GATSBY 爆水擦澡濕巾等近門檻真同款可被回收;未放寬 `MIN_MATCH_SCORE`。同版保留 peripera 多色任選對單一色號、LUNASOL 頰彩對眼彩組、MUJI 細軸棉棒對黑色棉棒的低信心保護,並讓多組件套組即使達強身份證據也停在 `identity_review`,避免總價被誤當精準價格告警。 diff --git a/services/marketplace_product_matcher.py b/services/marketplace_product_matcher.py index cd1b799..9dac17f 100644 --- a/services/marketplace_product_matcher.py +++ b/services/marketplace_product_matcher.py @@ -2683,6 +2683,21 @@ def _has_pavaruni_20_scent_candle_alignment(left: ProductIdentity, right: Produc ) +def _has_laundrin_tokyo_car_freshener_alignment(left: ProductIdentity, right: ProductIdentity) -> bool: + left_text = left.searchable_name + right_text = right.searchable_name + return ( + {"laundrin", "朗德林"} & (left.brand_tokens & right.brand_tokens) + and "tokyo" in left_text + and "tokyo" in right_text + and "車用" in left_text + and "車用" in right_text + and "芳香劑" in left_text + and "芳香劑" in right_text + and _has_shared_count(left, right, 1, "入") + ) + + def _has_shared_count(left: ProductIdentity, right: ProductIdentity, count: int, unit: str) -> bool: return (count, unit) in set(left.counts) and (count, unit) in set(right.counts) @@ -2846,16 +2861,7 @@ def _has_focused_low_score_exact_identity_line(left: ProductIdentity, right: Pro return "pavaruni_40_scent_oil" if _has_pavaruni_20_scent_candle_alignment(left, right): return "pavaruni_20_scent_candle" - if ( - {"laundrin", "朗德林"} & (left.brand_tokens & right.brand_tokens) - and "tokyo" in left_text - and "tokyo" in right_text - and "車用" in left_text - and "車用" in right_text - and "芳香劑" in left_text - and "芳香劑" in right_text - and _has_shared_count(left, right, 1, "入") - ): + if _has_laundrin_tokyo_car_freshener_alignment(left, right): return "laundrin_tokyo_car_freshener" if ( "好物良品" in (left.brand_tokens & right.brand_tokens) @@ -2877,7 +2883,7 @@ def _has_focused_low_score_exact_identity_line(left: ProductIdentity, right: Pro and "乳霜" in left_text and "乳霜" in right_text and _has_shared_weight(left, right, 30) - and _has_shared_count(left, right, 6, "入") + and _has_exact_count_alignment(left, right) ): return "yuskin_classic_cream_30g_6pack" if ( @@ -2950,6 +2956,8 @@ def _has_variant_descriptor_conflict(left: ProductIdentity, right: ProductIdenti return False if _has_pavaruni_20_scent_candle_alignment(left, right): return False + if _has_laundrin_tokyo_car_freshener_alignment(left, right): + return False if _is_relove_private_cleanser_line(left, right): return False if (