refactor(routes): 刪除模組化死碼開關
ADR-017 Phase 3f-1 dead-switch sprint;改為直接註冊 Blueprint,移除 USE_MODULAR_ROUTES/register_blueprints,並加入重複路由啟動自檢。
This commit is contained in:
95
app.py
95
app.py
@@ -338,27 +338,45 @@ try:
|
||||
except Exception as _e:
|
||||
sys_log.error(f"[Blueprint] ❌ OpenClaw Bot Blueprint 註冊失敗: {_e}")
|
||||
|
||||
# P0-12 修復:補齊缺少的 Blueprint 註冊
|
||||
for _bp_module, _bp_name in [
|
||||
('routes.api_routes', 'api_bp'),
|
||||
('routes.edm_routes', 'edm_bp'),
|
||||
('routes.sales_routes', 'sales_bp'),
|
||||
('routes.monthly_routes', 'monthly_bp'),
|
||||
('routes.price_comparison_routes', 'price_comparison_bp'),
|
||||
('routes.export_routes', 'export_bp'),
|
||||
('routes.daily_sales_routes', 'daily_sales_bp'),
|
||||
('routes.dashboard_routes', 'dashboard_bp'),
|
||||
('routes.import_routes', 'import_bp'),
|
||||
('routes.pchome_routes', 'pchome_bp'),
|
||||
]:
|
||||
try:
|
||||
import importlib as _il
|
||||
_mod = _il.import_module(_bp_module)
|
||||
_bp = getattr(_mod, _bp_name)
|
||||
app.register_blueprint(_bp)
|
||||
sys_log.info(f"[Blueprint] ✅ {_bp_name} 已註冊")
|
||||
except Exception as _e:
|
||||
sys_log.error(f"[Blueprint] ❌ {_bp_name} 註冊失敗: {_e}")
|
||||
from routes.api_routes import api_bp
|
||||
app.register_blueprint(api_bp)
|
||||
sys_log.info("[Blueprint] ✅ api_bp 已註冊")
|
||||
|
||||
from routes.edm_routes import edm_bp
|
||||
app.register_blueprint(edm_bp)
|
||||
sys_log.info("[Blueprint] ✅ edm_bp 已註冊")
|
||||
|
||||
from routes.sales_routes import sales_bp
|
||||
app.register_blueprint(sales_bp)
|
||||
sys_log.info("[Blueprint] ✅ sales_bp 已註冊")
|
||||
|
||||
from routes.monthly_routes import monthly_bp
|
||||
app.register_blueprint(monthly_bp)
|
||||
sys_log.info("[Blueprint] ✅ monthly_bp 已註冊")
|
||||
|
||||
from routes.price_comparison_routes import price_comparison_bp
|
||||
app.register_blueprint(price_comparison_bp)
|
||||
sys_log.info("[Blueprint] ✅ price_comparison_bp 已註冊")
|
||||
|
||||
from routes.export_routes import export_bp
|
||||
app.register_blueprint(export_bp)
|
||||
sys_log.info("[Blueprint] ✅ export_bp 已註冊")
|
||||
|
||||
from routes.daily_sales_routes import daily_sales_bp
|
||||
app.register_blueprint(daily_sales_bp)
|
||||
sys_log.info("[Blueprint] ✅ daily_sales_bp 已註冊")
|
||||
|
||||
from routes.dashboard_routes import dashboard_bp
|
||||
app.register_blueprint(dashboard_bp)
|
||||
sys_log.info("[Blueprint] ✅ dashboard_bp 已註冊")
|
||||
|
||||
from routes.import_routes import import_bp
|
||||
app.register_blueprint(import_bp)
|
||||
sys_log.info("[Blueprint] ✅ import_bp 已註冊")
|
||||
|
||||
from routes.pchome_routes import pchome_bp
|
||||
app.register_blueprint(pchome_bp)
|
||||
sys_log.info("[Blueprint] ✅ pchome_bp 已註冊")
|
||||
|
||||
# V-Fix: 註冊 slugify 函數供模板使用(實作搬至 utils/text_helpers.py)
|
||||
from utils.text_helpers import slugify # noqa: E402
|
||||
@@ -624,36 +642,19 @@ def refresh_session():
|
||||
session.modified = True # 標記 Session 已修改,觸發 Cookie 更新
|
||||
|
||||
|
||||
def verify_unique_routes():
|
||||
"""啟動期防線:同一 URL + method 不得由兩個 endpoint 同時註冊。"""
|
||||
seen = {}
|
||||
for rule in app.url_map.iter_rules():
|
||||
key = (str(rule), frozenset(rule.methods - {'HEAD', 'OPTIONS'}))
|
||||
if key in seen:
|
||||
raise SystemExit(f"重複路由: {key} 來自 {seen[key]} 與 {rule.endpoint}")
|
||||
seen[key] = rule.endpoint
|
||||
|
||||
|
||||
verify_unique_routes()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# ================= 📊 V-New: 業績分析報表 =================
|
||||
|
||||
|
||||
|
||||
|
||||
# V-Opt: API 層級快取 (減少重複查詢)
|
||||
_TABLE_DATA_CACHE = {}
|
||||
_TABLE_DATA_CACHE_TTL = 60 # 快取 60 秒
|
||||
|
||||
|
||||
|
||||
# V-Old: 保留舊版本以防需要回滾
|
||||
|
||||
# ================= 💎 V-New: Top 3 Highlights 詳細列表 API =================
|
||||
|
||||
|
||||
# ================= 📈 V-New: 年度對比 (Year-over-Year Comparison) =================
|
||||
|
||||
# ================= 📈 V-New: 營運成長報表 (Growth Strategy) =================
|
||||
|
||||
def preprocess_daily_sales_data(df):
|
||||
"""前處理當日業績資料:欄位識別、型別轉換"""
|
||||
cols = df.columns.tolist()
|
||||
|
||||
19
config.py
19
config.py
@@ -237,23 +237,6 @@ SYSTEM_VERSION = "V10.3"
|
||||
LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log')
|
||||
public_url = PUBLIC_URL # 用於模板顯示
|
||||
|
||||
# ==========================================
|
||||
# 模組化路由設定
|
||||
# ==========================================
|
||||
# 控制是否啟用模組化路由,設為 True 時會自動清理 app.py 中的重複路由
|
||||
USE_MODULAR_ROUTES = {
|
||||
'system': True, # 系統設定、日誌、備份
|
||||
'edm': True, # EDM 與節慶儀表板
|
||||
'monthly': True, # 月結分析
|
||||
'dashboard': True, # 首頁商品看板
|
||||
'daily_sales': True, # 當日業績分析
|
||||
'api': True, # 通用 API
|
||||
'export': True, # 匯出功能
|
||||
'import': True, # 匯入功能
|
||||
'sales': True, # 業績分析
|
||||
}
|
||||
|
||||
|
||||
def validate_critical_config():
|
||||
"""啟動時驗證選用配置,缺少則回傳 warning 清單(非 fatal)。"""
|
||||
warnings = []
|
||||
@@ -261,4 +244,4 @@ def validate_critical_config():
|
||||
for var in optional_vars:
|
||||
if not os.getenv(var):
|
||||
warnings.append(f"[Config] 選用設定 {var} 未設,部分功能可能停用")
|
||||
return warnings
|
||||
return warnings
|
||||
|
||||
168
routes/README.md
168
routes/README.md
@@ -1,154 +1,26 @@
|
||||
# 路由模組重構說明
|
||||
# 路由模組說明
|
||||
|
||||
## 概述
|
||||
`app.py` 直接註冊所有 Flask Blueprint;`USE_MODULAR_ROUTES`、`register_blueprints()`、
|
||||
`MODULAR_ENDPOINTS` 與 duplicate cleanup 開關已在 ADR-017 Phase 3f-1 移除。
|
||||
|
||||
此目錄包含從 `app.py` 中分離出來的路由模組,採用 Flask Blueprint 架構。
|
||||
這樣的模組化設計使得代碼更易於維護、測試和擴展。
|
||||
## 啟動防線
|
||||
|
||||
`app.py` 會在啟動時檢查 `app.url_map`,同一組 `(URL, HTTP methods)` 不允許被兩個 endpoint
|
||||
重複註冊;若發現衝突會直接 `SystemExit`。
|
||||
|
||||
## 模組清單
|
||||
|
||||
| 模組 | 狀態 | 說明 | 路由 |
|
||||
|------|------|------|------|
|
||||
| `system_routes.py` | ✅ 獨立 | 系統管理 | `/settings`, `/logs`, `/health`, `/metrics`, `/api/backup` 等 |
|
||||
| `edm_routes.py` | ✅ 獨立 | EDM 儀表板 | `/edm`, `/festival` |
|
||||
| `monthly_routes.py` | ✅ 獨立 | 月結分析 | `/monthly_summary_analysis`, `/api/monthly_summary_data` |
|
||||
| `dashboard_routes.py` | ✅ 獨立 | 首頁看板 | `/`, `/brand_assets` |
|
||||
| `daily_sales_routes.py` | ✅ 獨立 | 當日業績 | `/daily_sales`, `/daily_sales/export*` |
|
||||
| `api_routes.py` | ✅ 已獨立 | 通用 API | `/api/run_task`, `/api/history/*` 等 |
|
||||
| `export_routes.py` | ✅ 已獨立 | 匯出功能 | `/api/export/*` |
|
||||
| `import_routes.py` | ✅ 已獨立 | 匯入功能 | `/api/import_excel`, `/api/import/monthly_summary` |
|
||||
| `sales_routes.py` | ⚡ 延遲導入 | 業績分析 | `/sales_analysis`, `/growth_analysis`, `/api/sales_analysis/*` |
|
||||
| 模組 | 說明 | 主要路由 |
|
||||
|------|------|----------|
|
||||
| `dashboard_routes.py` | 商品看板首頁 | `/` |
|
||||
| `sales_routes.py` | 業績分析與 ABC 明細 | `/sales_analysis`, `/growth_analysis`, `/abc_analysis/detail`, `/api/sales_analysis/*` |
|
||||
| `system_public_routes.py` | 無 prefix 公開系統頁與監控 | `/health`, `/metrics`, `/settings`, `/system_settings`, `/logs`, `/api/logs`, `/api/backup` |
|
||||
| `system_routes.py` | 內部系統維護 API | `/api/system/*` |
|
||||
| `edm_routes.py` | EDM 與節慶儀表板 | `/edm`, `/festival` |
|
||||
| `monthly_routes.py` | 月結分析 | `/monthly_summary_analysis`, `/api/monthly_summary_data` |
|
||||
| `daily_sales_routes.py` | 當日業績 | `/daily_sales`, `/daily_sales/export*` |
|
||||
| `api_routes.py` | 通用任務與查詢 API | `/api/run_task`, `/api/history/*` |
|
||||
| `export_routes.py` | 匯出功能 | `/api/export/*` |
|
||||
| `import_routes.py` | 匯入功能 | `/api/import_excel`, `/api/import/monthly_summary` |
|
||||
|
||||
## 啟用模組
|
||||
|
||||
### 方法一:修改 config.py(推薦)
|
||||
|
||||
在 `config.py` 中設定 `USE_MODULAR_ROUTES`:
|
||||
|
||||
```python
|
||||
USE_MODULAR_ROUTES = {
|
||||
'system': True, # 啟用 system_routes
|
||||
'edm': True, # 啟用 edm_routes
|
||||
'monthly': True, # 啟用 monthly_routes
|
||||
'dashboard': True, # 啟用 dashboard_routes
|
||||
'daily_sales': True, # 啟用 daily_sales_routes
|
||||
'api': False, # api_routes 有依賴,暫不啟用
|
||||
'export': False, # export_routes 有依賴,暫不啟用
|
||||
'import': False, # import_routes 有依賴,暫不啟用
|
||||
'sales': False, # sales_routes 有依賴,暫不啟用
|
||||
}
|
||||
```
|
||||
|
||||
### 方法二:環境變數
|
||||
|
||||
可透過環境變數覆蓋設定(待實作)。
|
||||
|
||||
## 運作原理
|
||||
|
||||
1. **Blueprint 註冊**:`routes/__init__.py` 中的 `register_blueprints()` 函數根據 `USE_MODULAR_ROUTES` 設定決定是否註冊各模組的 Blueprint。
|
||||
|
||||
2. **重複路由清理**:`app.py` 底部的 `cleanup_duplicate_routes()` 函數會在所有路由定義完成後,移除與已啟用 Blueprint 重複的路由。
|
||||
|
||||
3. **優先順序**:Blueprint 中的路由優先於 app.py 中的同名路由。
|
||||
|
||||
## 模組依賴說明
|
||||
|
||||
### 完全獨立模組
|
||||
- `system_routes.py`
|
||||
- `edm_routes.py`
|
||||
- `monthly_routes.py`
|
||||
- `dashboard_routes.py` - 提供 `get_consolidated_data`, `get_dashboard_stats`
|
||||
- `daily_sales_routes.py`
|
||||
|
||||
這些模組不依賴 app.py 中的任何函數或變數。
|
||||
|
||||
### 已獨立化的模組(使用 services 或其他獨立模組)
|
||||
- `api_routes.py`:
|
||||
- 使用 `services/task_runner.py` 中的 `run_momo_task_with_notification`
|
||||
- 使用 `routes/dashboard_routes.py` 中的 `get_dashboard_stats`
|
||||
- `export_routes.py`:
|
||||
- 使用 `routes/dashboard_routes.py` 中的 `get_consolidated_data`
|
||||
- 使用 `services/cache_service.py` 中的快取變數
|
||||
- `import_routes.py`:
|
||||
- 使用 `services/cache_service.py` 中的 `_SALES_DF_CACHE`, `_SALES_PROCESSED_CACHE`
|
||||
|
||||
### 延遲導入模組
|
||||
- `sales_routes.py`:
|
||||
- `growth_analysis()` 已完全獨立
|
||||
- 其他 API 函數使用延遲導入從 app.py 取得(函數邏輯複雜,暫不遷移)
|
||||
|
||||
## 開發指南
|
||||
|
||||
### 新增路由模組
|
||||
|
||||
1. 在 `routes/` 目錄建立新的 Python 檔案
|
||||
2. 定義 Blueprint:
|
||||
```python
|
||||
from flask import Blueprint
|
||||
my_bp = Blueprint('my_module', __name__)
|
||||
```
|
||||
3. 在 `routes/__init__.py` 中加入註冊邏輯
|
||||
4. 在 `config.py` 的 `USE_MODULAR_ROUTES` 中加入控制項
|
||||
|
||||
### 從 app.py 遷移路由
|
||||
|
||||
1. 複製路由函數到對應模組
|
||||
2. 將 `@app.route` 改為 `@blueprint_name.route`
|
||||
3. 確認所有導入正確
|
||||
4. 測試模組可正常導入:`python -c "from routes.xxx import xxx_bp"`
|
||||
5. 在 `MODULAR_ENDPOINTS` 中記錄端點名稱
|
||||
|
||||
## 測試
|
||||
|
||||
測試模組是否正常運作:
|
||||
|
||||
```bash
|
||||
# 測試所有模組導入
|
||||
python -c "
|
||||
from routes.system_routes import system_bp
|
||||
from routes.edm_routes import edm_bp
|
||||
from routes.monthly_routes import monthly_bp
|
||||
from routes.dashboard_routes import dashboard_bp
|
||||
from routes.daily_sales_routes import daily_sales_bp
|
||||
print('All independent modules imported successfully!')
|
||||
"
|
||||
|
||||
# 測試完整應用(啟用所有獨立模組)
|
||||
python -c "
|
||||
import config
|
||||
config.USE_MODULAR_ROUTES = {
|
||||
'system': True, 'edm': True, 'monthly': True,
|
||||
'dashboard': True, 'daily_sales': True,
|
||||
'api': False, 'export': False, 'import': False, 'sales': False
|
||||
}
|
||||
import app
|
||||
print(f'Total routes: {len(list(app.app.url_map.iter_rules()))}')
|
||||
"
|
||||
```
|
||||
|
||||
## 已知問題
|
||||
|
||||
### 模板 url_for 端點名稱問題
|
||||
|
||||
當啟用模組化路由時,端點名稱會從 `'index'` 變為 `'dashboard.index'`。
|
||||
這會導致模板中的 `url_for('index')` 調用失敗。
|
||||
|
||||
**影響範圍**:
|
||||
- `index.html` 中的 `url_for('index', ...)`
|
||||
- `edm_dashboard.html` 中的 `url_for('edm_dashboard', ...)`
|
||||
|
||||
**解決方案**(需在啟用模組前執行):
|
||||
1. 在模板中使用完整的端點名稱,如 `url_for('dashboard.index', ...)`
|
||||
2. 或在 app.py 中加入端點別名
|
||||
|
||||
**注意**:目前預設所有模組皆禁用(`USE_MODULAR_ROUTES` 全為 False),
|
||||
因此不會影響正常使用。此問題只會在手動啟用模組後出現。
|
||||
|
||||
## 變更歷史
|
||||
|
||||
- **2026-01-18**:
|
||||
- 初始版本,建立 9 個路由模組,5 個獨立模組可直接啟用
|
||||
- 修復 url_for 端點名稱問題,新增 `register_endpoint_aliases()` 函數
|
||||
- 處理有依賴的模組 (api, export, import),使用獨立 services 模組
|
||||
- 新增 `services/task_runner.py` 封裝爬蟲任務執行邏輯
|
||||
- 所有 9 個模組已啟用並通過測試
|
||||
新增 route 時請優先放入對應 Blueprint,並用本機 `app.url_map` duplicate check 驗證。
|
||||
|
||||
@@ -1,190 +1 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
路由模組 - Blueprint 註冊中心
|
||||
將所有路由模組集中管理,方便 app.py 統一註冊
|
||||
|
||||
重構狀態:
|
||||
所有模組已獨立化並啟用:
|
||||
- system_routes: 系統設定、日誌、備份 (完全獨立)
|
||||
- edm_routes: EDM 與節慶儀表板 (完全獨立)
|
||||
- monthly_routes: 月結分析 (完全獨立)
|
||||
- dashboard_routes: 首頁商品看板 (完全獨立)
|
||||
- daily_sales_routes: 當日業績分析 (完全獨立)
|
||||
- api_routes: 通用 API (使用 task_runner, dashboard_routes)
|
||||
- export_routes: 匯出功能 (使用 dashboard_routes, cache_service)
|
||||
- import_routes: 匯入功能 (使用 cache_service)
|
||||
- sales_routes: 業績分析 (延遲導入 app.py 複雜函數)
|
||||
|
||||
啟用方式:
|
||||
1. 在 config.py 中將對應的 USE_MODULAR_ROUTES[key] 設為 True
|
||||
2. 重啟應用程式
|
||||
3. app.py 中的對應路由會自動被跳過 (cleanup_duplicate_routes)
|
||||
4. url_for 向後相容透過 register_endpoint_aliases 實現
|
||||
"""
|
||||
|
||||
from config import USE_MODULAR_ROUTES
|
||||
|
||||
# 記錄已被模組化路由覆蓋的端點名稱
|
||||
MODULAR_ENDPOINTS = set()
|
||||
|
||||
|
||||
def register_blueprints(app):
|
||||
"""
|
||||
註冊所有 Blueprint 到 Flask app
|
||||
|
||||
Args:
|
||||
app: Flask 應用程式實例
|
||||
"""
|
||||
global MODULAR_ENDPOINTS
|
||||
registered = []
|
||||
errors = []
|
||||
|
||||
# ============================================================
|
||||
# 第一階段:完全獨立的模組(無 app.py 依賴)
|
||||
# 透過 config.USE_MODULAR_ROUTES 控制是否啟用
|
||||
# ============================================================
|
||||
|
||||
# 系統管理路由 (設定、日誌、備份、分類管理)
|
||||
if USE_MODULAR_ROUTES.get('system', False):
|
||||
try:
|
||||
from routes.system_routes import system_bp
|
||||
app.register_blueprint(system_bp)
|
||||
registered.append('system_routes')
|
||||
# 記錄此模組覆蓋的端點
|
||||
MODULAR_ENDPOINTS.update([
|
||||
'health_check', 'prometheus_metrics', 'settings', 'system_settings_page',
|
||||
'add_category', 'update_category', 'delete_category', 'test_url',
|
||||
'show_logs', 'get_logs_api', 'trigger_backup', 'download_backup'
|
||||
])
|
||||
except ImportError as e:
|
||||
errors.append(f"system_routes: {e}")
|
||||
|
||||
# EDM 與節慶儀表板路由
|
||||
if USE_MODULAR_ROUTES.get('edm', False):
|
||||
try:
|
||||
from routes.edm_routes import edm_bp
|
||||
app.register_blueprint(edm_bp)
|
||||
registered.append('edm_routes')
|
||||
MODULAR_ENDPOINTS.update(['edm_dashboard', 'festival_dashboard'])
|
||||
except ImportError as e:
|
||||
errors.append(f"edm_routes: {e}")
|
||||
|
||||
# 月結分析路由
|
||||
if USE_MODULAR_ROUTES.get('monthly', False):
|
||||
try:
|
||||
from routes.monthly_routes import monthly_bp
|
||||
app.register_blueprint(monthly_bp)
|
||||
registered.append('monthly_routes')
|
||||
MODULAR_ENDPOINTS.update(['monthly_summary_analysis_page', 'get_monthly_summary_data'])
|
||||
except ImportError as e:
|
||||
errors.append(f"monthly_routes: {e}")
|
||||
|
||||
# 商品看板路由 (首頁)
|
||||
if USE_MODULAR_ROUTES.get('dashboard', False):
|
||||
try:
|
||||
from routes.dashboard_routes import dashboard_bp
|
||||
app.register_blueprint(dashboard_bp)
|
||||
registered.append('dashboard_routes')
|
||||
MODULAR_ENDPOINTS.update(['index', 'brand_assets'])
|
||||
except ImportError as e:
|
||||
errors.append(f"dashboard_routes: {e}")
|
||||
|
||||
# 當日業績路由
|
||||
if USE_MODULAR_ROUTES.get('daily_sales', False):
|
||||
try:
|
||||
from routes.daily_sales_routes import daily_sales_bp
|
||||
app.register_blueprint(daily_sales_bp)
|
||||
registered.append('daily_sales_routes')
|
||||
MODULAR_ENDPOINTS.update([
|
||||
'daily_sales', 'export_daily_sales_category', 'export_marketing_summary_excel'
|
||||
])
|
||||
except ImportError as e:
|
||||
errors.append(f"daily_sales_routes: {e}")
|
||||
|
||||
# ============================================================
|
||||
# 第二階段:有 app.py 依賴的模組(暫時保留在 app.py)
|
||||
# ============================================================
|
||||
|
||||
# 通用 API 路由 - 依賴: scheduled_job_wrapper, get_dashboard_stats
|
||||
if USE_MODULAR_ROUTES.get('api', False):
|
||||
try:
|
||||
from routes.api_routes import api_bp
|
||||
app.register_blueprint(api_bp)
|
||||
registered.append('api_routes')
|
||||
MODULAR_ENDPOINTS.update([
|
||||
'trigger_task', 'trigger_edm_task', 'trigger_festival_task',
|
||||
'trigger_momo_notification', 'trigger_edm_notification', 'test_notification',
|
||||
'get_price_history', 'get_price_change_details'
|
||||
])
|
||||
except ImportError as e:
|
||||
errors.append(f"api_routes: {e}")
|
||||
|
||||
# 匯出功能路由 - 依賴: get_consolidated_data, _SALES_PROCESSED_CACHE
|
||||
if USE_MODULAR_ROUTES.get('export', False):
|
||||
try:
|
||||
from routes.export_routes import export_bp
|
||||
app.register_blueprint(export_bp)
|
||||
registered.append('export_routes')
|
||||
except ImportError as e:
|
||||
errors.append(f"export_routes: {e}")
|
||||
|
||||
# 匯入功能路由 - 依賴: _SALES_DF_CACHE, _SALES_PROCESSED_CACHE
|
||||
if USE_MODULAR_ROUTES.get('import', False):
|
||||
try:
|
||||
from routes.import_routes import import_bp
|
||||
app.register_blueprint(import_bp)
|
||||
registered.append('import_routes')
|
||||
except ImportError as e:
|
||||
errors.append(f"import_routes: {e}")
|
||||
|
||||
# 業績分析路由 - 依賴: 多個複雜函數
|
||||
if USE_MODULAR_ROUTES.get('sales', False):
|
||||
try:
|
||||
from routes.sales_routes import sales_bp
|
||||
app.register_blueprint(sales_bp)
|
||||
registered.append('sales_routes')
|
||||
MODULAR_ENDPOINTS.update([
|
||||
'sales_analysis', 'growth_analysis',
|
||||
'api_sales_table_data', 'api_sales_table_data_pandas',
|
||||
'api_sales_top_detail', 'api_export_top_detail', 'api_yoy_comparison'
|
||||
])
|
||||
except ImportError as e:
|
||||
errors.append(f"sales_routes: {e}")
|
||||
|
||||
# AI 推薦路由 - Ollama LLM 整合
|
||||
if USE_MODULAR_ROUTES.get('ai', False):
|
||||
try:
|
||||
from routes.ai_routes import ai_bp
|
||||
app.register_blueprint(ai_bp)
|
||||
registered.append('ai_routes')
|
||||
MODULAR_ENDPOINTS.update([
|
||||
'ai_recommend', 'ai_status', 'ai_trends', 'ai_weather',
|
||||
'ai_generate_copy', 'ai_recommend_products', 'ai_analyze_weather_products',
|
||||
'ai_batch_generate_copy'
|
||||
])
|
||||
except ImportError as e:
|
||||
errors.append(f"ai_routes: {e}")
|
||||
|
||||
# 輸出註冊結果
|
||||
if registered:
|
||||
print(f"✅ 已註冊路由模組: {', '.join(registered)}")
|
||||
if errors:
|
||||
for err in errors:
|
||||
print(f"⚠️ 模組載入失敗: {err}")
|
||||
|
||||
if not registered and not errors:
|
||||
print("ℹ️ 路由模組重構中,透過 config.USE_MODULAR_ROUTES 控制啟用")
|
||||
|
||||
|
||||
def is_endpoint_modular(endpoint_name):
|
||||
"""
|
||||
檢查指定的端點是否已被模組化路由覆蓋
|
||||
|
||||
Args:
|
||||
endpoint_name: 端點函數名稱
|
||||
|
||||
Returns:
|
||||
bool: True 表示已被模組化,app.py 應跳過此路由
|
||||
"""
|
||||
return endpoint_name in MODULAR_ENDPOINTS
|
||||
"""Blueprint route package."""
|
||||
|
||||
Reference in New Issue
Block a user