修正 AI 推薦頁 Gemini 主路徑顯示
All checks were successful
CD Pipeline / deploy (push) Successful in 1m4s

This commit is contained in:
OoO
2026-05-21 16:24:51 +08:00
committed by AiderHeal Bot
parent e3da4ffbb3
commit c7fdd57156
4 changed files with 66 additions and 4 deletions

View File

@@ -325,7 +325,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '')
# ==========================================
# 系統版本與路徑
# ==========================================
SYSTEM_VERSION = "V10.377"
SYSTEM_VERSION = "V10.378"
LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log')
public_url = PUBLIC_URL # 用於模板顯示

View File

@@ -13,6 +13,7 @@
## 📅 詳細更新日誌 (考古存檔)
### 2026-05-21瀏覽器測試守門與 PChome 熱路徑優化
- **V10.378 AI 推薦頁首屏 Gemini 防漏**: `/ai_recommend` 首屏狀態快照新增 provider sanitization即使舊 cache / env 內出現 `default_provider='gemini'``recommended_provider='gemini'`,也會回到 `ollama`,避免 UI 把 Gemini 顯示成主推薦路徑;`/api/ai/set_provider` 同步正規化 provider 輸入,保留 Gemini 只能作 Ollama 失敗備援的拒絕訊息。
- **V10.377 Gemini 主路徑防漏補強**: `AIProviderService._get_recommended_provider()` 不再於 Ollama 不通時推薦 `gemini` 作為主提供者;`llm_model_router``ea_engine` 即使 caller 傳入 `gemini-2.0-flash` default也會改回 `hermes3:latest`,需要深推理才升 `deepseek-r1:14b``ElephantAlphaOrchestrator` 的 OpenClaw registry / system prompt 改為 Ollama-first避免 L3 HITL prompt 繼續把 Gemini 當主模型描述。同步補 AI SOT 與防回歸測試。
- **V10.376 Recipe Box 同款防曬漂移比對**: `services/marketplace_product_matcher.py` 對 Recipe Box 多效提亮防曬霜新增 shared identity anchor 加分,當 MOMO 長標含兒童/無毒/天然彩妝等行銷詞、PChome 以「韓兔 多效提亮防曬霜」呈現時仍可判定同款;同步測試鎖住 `shared_identity_anchor_recipe_box_line`,避免平台名稱漂移讓同款價格告警漏報。
- **V10.375 過期活動爬蟲排程 opt-in**: `run_scheduler.py` 將固定 LPN 的 `edm_task` / `festival_task` 改為 `MOMO_ENABLE_LEGACY_EDM_SCHEDULE=true` 才註冊,季節活動 `mothers_day_2026` / `valentine_520_2026` / `labor_day_2026` 改為 `MOMO_ENABLE_SEASONAL_PROMO_SCHEDULE=true` 才註冊;`services/data/crawler_config.json` 同步暫停已失效的 mothers_day LPN避免 scheduler 定時打過期 MOMO 活動頁造成 Selenium browser loop 與無效負載。手動 API / CLI 指定 LPN 仍保留;同版整合 NIVEA/OPI 等比價搜尋 noise 與 identity anchor 補強。

View File

@@ -45,15 +45,35 @@ ai_history_service = AIHistoryService()
ai_template_service = AITemplateService()
def _safe_primary_provider(provider: str | None) -> str:
normalized = (provider or 'ollama').strip().lower()
if normalized == 'gemini':
return 'ollama'
if normalized in ('ollama', 'elephant'):
return normalized
return 'ollama'
def _safe_recommended_provider(provider: str | None) -> str:
"""Initial render must never advertise Gemini as a primary provider."""
normalized = _safe_primary_provider(provider)
return normalized if normalized in ('ollama', 'elephant') else 'none'
def _get_ai_status_for_initial_render():
"""取得首屏用 AI 狀態快照,不做同步網路健康檢查。"""
status_cache = getattr(ai_provider_service, '_status_cache', {}) or {}
cached_status = status_cache.get('data')
if cached_status:
cached_status = dict(cached_status)
cached_status['default_provider'] = _safe_primary_provider(cached_status.get('default_provider'))
cached_status['recommended_provider'] = _safe_recommended_provider(
cached_status.get('recommended_provider') or cached_status.get('default_provider')
)
return cached_status
default_model = getattr(ollama_service, 'model', None) or 'gemma3:4b'
default_provider = getattr(ai_provider_service, 'default_provider', 'ollama')
default_provider = _safe_primary_provider(getattr(ai_provider_service, 'default_provider', 'ollama'))
return {
'default_provider': default_provider,
'ollama': {
@@ -77,7 +97,7 @@ def _get_ai_status_for_initial_render():
'type': 'cloud',
'cost': 'efficient',
},
'recommended_provider': default_provider,
'recommended_provider': _safe_recommended_provider(default_provider),
'timestamp': None,
}
@@ -122,7 +142,7 @@ def api_set_provider():
"""切換預設 AI 提供者"""
try:
data = request.get_json()
provider = data.get('provider', 'ollama')
provider = (data.get('provider', 'ollama') or 'ollama').strip().lower()
if provider == 'gemini':
return jsonify({

View File

@@ -0,0 +1,41 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""AI recommendation route Ollama-first display contract."""
def test_initial_ai_status_sanitizes_cached_gemini_recommendation(monkeypatch):
import routes.ai_routes as ai_routes
monkeypatch.setattr(
ai_routes.ai_provider_service,
"_status_cache",
{
"data": {
"default_provider": "gemini",
"recommended_provider": "gemini",
"ollama": {"connected": None},
"gemini": {"connected": True},
}
},
)
status = ai_routes._get_ai_status_for_initial_render()
assert status["default_provider"] == "ollama"
assert status["recommended_provider"] == "ollama"
def test_initial_ai_status_never_recommends_gemini_without_cache(monkeypatch):
import routes.ai_routes as ai_routes
class FakeProvider:
default_provider = "gemini"
_status_cache = {}
monkeypatch.setattr(ai_routes, "ai_provider_service", FakeProvider())
status = ai_routes._get_ai_status_for_initial_render()
assert status["default_provider"] == "ollama"
assert status["recommended_provider"] == "ollama"