Fix Telegram bot natural language communication issue

- Install python-telegram-bot dependency
- Start Telegram bot service successfully
- Confirm correct group ID (MOMO PRO - small shrimp group)
- Bot now running with all commands and button interface functional
- Natural language processing restored with keyword matching

Fixes issue where Telegram group could not communicate using natural language.
This commit is contained in:
ogt
2026-04-22 14:25:57 +08:00
parent 9c7b794a22
commit a96306fba2
11 changed files with 1668 additions and 14 deletions

114
.github/workflows/code-review.yml vendored Normal file
View File

@@ -0,0 +1,114 @@
name: Aider Code Review
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
workflow_dispatch:
inputs:
review_type:
description: 'Type of code review'
required: true
default: 'basic'
type: choice
options:
- basic
- security
- performance
target_files:
description: 'Specific files to review (optional, comma-separated)'
required: false
type: string
jobs:
code-review:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # 獲取完整的Git歷史
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install aider-chat
# 如果有requirements.txt也安裝專案依賴
if [ -f requirements.txt ]; then
pip install -r requirements.txt
fi
- name: Configure Git
run: |
git config --global user.name "GitHub Actions"
git config --global user.email "actions@github.com"
- name: Run Code Review
run: |
# 創建logs目錄
mkdir -p logs
# 確定要review的檔案
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ -n "${{ github.event.inputs.target_files }}" ]; then
# 手動觸發,指定檔案
IFS=',' read -ra FILES <<< "${{ github.event.inputs.target_files }}"
python scripts/code_review.py --files "${FILES[@]}" --type "${{ github.event.inputs.review_type }}"
elif [ "${{ github.event_name }}" = "pull_request" ]; then
# PRreview變更的檔案
git diff origin/${{ github.base_ref }}...HEAD --name-only --diff-filter=ACM | grep -E '\.(py|js|ts|jsx|tsx|html|css)$' > /tmp/changed_files.txt
if [ -s /tmp/changed_files.txt ]; then
python scripts/code_review.py --files $(cat /tmp/changed_files.txt | tr '\n' ' ') --type basic
else
echo "No files to review"
fi
else
# Pushreview暫存的檔案
python scripts/code_review.py --auto --type basic
fi
- name: Upload review reports
uses: actions/upload-artifact@v3
if: always()
with:
name: code-review-reports
path: logs/review_*.md
retention-days: 30
- name: Comment PR with review results
if: github.event_name == 'pull_request'
uses: actions/github-script@v6
with:
script: |
const fs = require('fs');
const path = './logs';
try {
const files = fs.readdirSync(path);
const reviewFiles = files.filter(f => f.startsWith('review_') && f.endsWith('.md'));
if (reviewFiles.length > 0) {
let comment = '## 🔍 Aider Code Review 報告\n\n';
reviewFiles.forEach(file => {
const content = fs.readFileSync(`${path}/${file}`, 'utf8');
comment += `### ${file}\n\n`;
comment += '```\n' + content + '\n```\n\n';
});
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});
}
} catch (error) {
console.log('No review reports found or error reading reports:', error.message);
}

259
CODE_REVIEW_GUIDE.md Normal file
View File

@@ -0,0 +1,259 @@
# 📋 MOMO 系統 - Aider Code Review 使用指南
## 🎯 功能概述
本系統整合了 Aider AI Code Review 功能,提供多種自動化程式碼審查方式,確保程式碼品質與安全性。
## 🚀 使用方式
### 1. **Git Hooks 自動觸發**
```bash
# 在 commit 時自動執行 Code Review
git add .
git commit -m "feat: 新增功能"
```
- ✅ 自動檢查暫存檔案
- ✅ Review 失敗時阻止 commit
- ✅ 支援跳過:`git commit --no-verify`
### 2. **手動快速觸發**
```bash
# 互動式選單
./scripts/quick_review.sh
# 直接指定檔案
./scripts/quick_review.sh app.py routes/sales_routes.py
# 自動 Review 暫存檔案
python3 scripts/code_review.py --auto
```
### 3. **Web 介面操作**
```bash
# 啟動 MOMO 系統
python3 app.py
# 訪問 Code Review 頁面
http://localhost:5000/code-review/
```
功能:
- 📁 檔案選擇器(支援變更檔案/所有檔案)
- 🔍 三種 Review 類型
- 📊 即時 Review 輸出
- 📈 Review 歷史記錄
- 📄 報告查看功能
### 4. **GitHub Actions CI/CD**
```bash
# 手動觸發
# 在 GitHub Actions 頁面選擇 "Aider Code Review" workflow
# 自動觸發
# Push 到 main/develop 分支
# 建立 Pull Request
```
## 🔧 Review 類型
### **基礎檢查 (Basic)**
- 程式碼品質與最佳實踐
- 潛在的 bug 與問題
- 程式碼可讀性與維護性
- 效能優化建議
### **安全檢查 (Security)**
- SQL 注入風險
- XSS 攻擊風險
- 認證與授權問題
- 敏感資料洩露風險
- 輸入驗證不足
### **效能檢查 (Performance)**
- 演算法效率
- 資料庫查詢優化
- 記憶體使用
- 並發處理
- 快取策略
## 📁 檔案結構
```
momo-pro-system/
├── scripts/
│ ├── code_review.py # 核心 Code Review 腳本
│ └── quick_review.sh # 快速觸發腳本
├── routes/
│ └── code_review_routes.py # Web 路由
├── templates/
│ └── code_review.html # Web 介面
├── .git/hooks/
│ └── pre-commit # Git Hook
├── .github/workflows/
│ └── code-review.yml # GitHub Actions
└── logs/
├── code_review.log # Review 日誌
└── review_*.md # Review 報告
```
## 🛠️ 進階設定
### **自訂 Review 提示詞**
編輯 `scripts/code_review.py` 中的 `message` 參數:
```python
# 基礎檢查範例
"--message", "請重點檢查:\n1. 程式碼架構設計\n2. 錯誤處理機制\n3. 日誌記錄完整性"
```
### **調整超時時間**
```python
# 在 code_review.py 中修改
timeout=600 # 10分鐘超時
```
### **支援的檔案類型**
```python
allowed_extensions = {
'.py', '.js', '.ts', '.jsx', '.tsx', '.html', '.css'
}
```
## 📊 查看結果
### **命令行查看**
```bash
# 查看 Review 日誌
tail -f logs/code_review.log
# 查看最新報告
ls -la logs/review_*.md | tail -1
cat logs/review_*.md | tail -1
```
### **Web 介面查看**
1. 訪問 `/code-review/`
2. 點擊「載入歷史記錄」
3. 點擊報告的「查看」按鈕
### **GitHub Actions 查看**
1. 前往 GitHub Actions 頁面
2. 查看 "Aider Code Review" workflow
3. 下載 "code-review-reports" artifact
## ⚠️ 注意事項
### **安全性**
- ✅ 所有敏感資料已過濾
- ✅ Review 結果僅儲存在本地
- ✅ GitHub Actions 使用隔離環境
### **效能**
- ⚠️ 大型專案建議分批 Review
- ⚠️ 複雜檔案可能需要更長時間
- ⚠️ 同時執行多個 Review 可能影響效能
### **相容性**
- ✅ 支援 Python 3.8+
- ✅ 需要 Aider 已安裝
- ✅ 相容 Git 2.0+
## 🔧 故障排除
### **常見問題**
**Q: Aider 執行失敗**
```bash
# 檢查 Aider 安裝
which aider
aider --version
# 重新安裝
pip install --upgrade aider-chat
```
**Q: Git Hook 不執行**
```bash
# 檢查權限
ls -la .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
# 測試執行
.git/hooks/pre-commit
```
**Q: Web 介面無法載入**
```bash
# 檢查 Blueprint 註冊
grep -n "code_review_bp" app.py
# 檢查路由
python3 -c "from routes.code_review_routes import code_review_bp; print(code_review_bp.url_prefix)"
```
### **除錯模式**
```bash
# 啟用詳細日誌
export DEBUG=1
python3 scripts/code_review.py --auto --type basic
# 測試模式(不實際執行 Aider
python3 -c "
from scripts.code_review import AiderCodeReview
reviewer = AiderCodeReview()
print('變更檔案:', reviewer.get_changed_files())
"
```
## 📚 API 參考
### **命令行參數**
```bash
python3 scripts/code_review.py [OPTIONS]
OPTIONS:
--files, -f 指定要 Review 的檔案
--type, -t Review 類型 (basic|security|performance)
--project-root, -p 專案根目錄路徑
--auto, -a 自動 Review 暫存檔案
--help, -h 顯示說明
```
### **Web API 端點**
```
GET /code-review/ # 主頁面
POST /code-review/api/start-review # 開始 Review
GET /code-review/api/get-changed-files # 獲取變更檔案
GET /code-review/api/review-history # Review 歷史
GET /code-review/api/view-report/<filename> # 查看報告
GET /code-review/api/get-project-files # 專案檔案列表
```
## 🎉 開始使用
1. **確保 Aider 已安裝**
```bash
pip install aider-chat
```
2. **測試基本功能**
```bash
./scripts/quick_review.sh
```
3. **設定 Git Hooks可選**
```bash
# 已自動設定,測試:
git add .
git commit -m "test: 測試 Code Review"
```
4. **啟動 Web 介面**
```bash
python3 app.py
# 訪問 http://localhost:5000/code-review/
```
---
*如有問題,請查看 `logs/code_review.log` 獲取詳細錯誤資訊。*

View File

@@ -0,0 +1,95 @@
---
title: "ADR-015: Telegram Bot 完整菜單系統恢復"
status: accepted
created: 2026-04-20
decision-date: 2026-04-20
authors:
- Cascade AI Assistant
---
# ADR-015: Telegram Bot 完整菜單系統恢復
## 狀況
用戶回報 Telegram Bot 菜單功能缺失,原本的 6 項簡單功能無法滿足完整業務需求。經檢查發現 `telegram_bot_service.py` 使用了簡化版菜單,而 `openclaw_bot_routes.py` 包含完整的 7 大類別菜單系統。
## 決策
恢復並實現完整的 Telegram Bot 菜單系統,包含:
1. **主菜單擴展**:從 6 項功能擴展為 7 大類別
2. **三層架構**:建立主菜單 → 子菜單 → 特定功能的層次結構
3. **完整功能覆蓋**:包含所有業務場景的菜單選項
4. **向下相容**:保留原有功能並新增缺失功能
## 實作
### 主菜單結構7大類別
```
📊 業績查詢 🏆 商品廠商
🎯 目標管理 📈 智能分析
📄 簡報報表 🌐 市場情報
🔍 競品日報
❓ 使用說明
```
### 子菜單系統10個完整子系統
1. **sales** - 業績查詢:今日/昨日/每週/每月/每季業績、趨勢分析、同期比較
2. **products** - 商品廠商:熱銷商品/廠商、商品健康、補貨預測、分類鑽取
3. **goals** - 目標管理:達成率查看、各週期目標設定
4. **analysis** - 智能分析:策略矩陣、業績趨勢、商品健康、促銷追蹤
5. **reports** - 簡報報表:各週期報告、策略分析、促銷效益、競品比較
6. **market** - 市場情報電商新聞、天氣、熱搜、口碑、匯率、節慶、YouTube、AI學習、比價
7. **competitor** - 競品日報:今日/昨日簡報、各週期比較
8. **competitor_ppt** - 競品PPT長週期半年/年比較(第三層)
9. **category** - 分類業績鑽取15個完整商品分類
10. **trend** - 業績趨勢:各時間範圍分析
### 關鍵發現
#### 市場情報完整功能恢復
原本遺漏的重要功能:
- 📰 電商新聞
- 🌤 台北天氣
- 🔥 Google熱搜
- 💬 Dcard口碑
- 💱 台銀匯率
- 📅 電商節慶
- ▶️ YouTube爆紅商品
- 🧠 AI學習狀態
- 🔍 關鍵字比價
- 📷 圖片比價說明
#### 三層菜單架構
- 第一層主菜單7大類別 + 使用說明)
- 第二層:各類別子菜單
- 第三層特定深入功能如競品PPT長週期
#### 15個完整分類
美妝保養、3C家電、服飾配件、居家生活、母嬰用品、生鮮食品、圖書文具、戶外運動、餐券票券、醫療保健、美體保健、寵物用品、箱包精品、車類百貨、情趣用品
## 結果
### 正面影響
-**功能完整性**從6項擴展為涵蓋所有業務場景的完整菜單系統
-**用戶體驗**:清晰的層次結構,便於導航和功能發現
-**業務覆蓋**:支援業績、商品、目標、分析、報表、市場、競品等全方位需求
-**向下相容**:保留原有功能,無破壞性變更
### 風險緩解
- **複雜性管理**:透過清晰的層次結構降低學習成本
- **維護負擔**:統一的菜單架構便於後續維護和擴展
## 後續行動
1. **監控使用情況**:觀察新菜單系統的用戶使用模式和反饋
2. **持續優化**:根據實際使用情況調整菜單結構
3. **文件更新**:更新相關的用戶手冊和操作指南
## 相關文件
- [ADR-012: Agent Action Ladder](./ADR-012-agent-action-ladder.md)
- [Telegram Bot 服務實作](../../services/telegram_bot_service.py)
- [OpenClaw Bot 路由](../../routes/openclaw_bot_routes.md)

View File

@@ -0,0 +1,305 @@
# ty-ai-standards 新專案接入指令書
> 本文件由統帥產生,可直接轉發給負責新專案的 Claude Code session。
> 執行前無需額外背景知識,照順序執行即可。
---
## 一、你的任務
將本機已建立的「ty-ai-standards 全域架構」套用到 **這個專案**
全域架構已就緒於 `~/.claude/`,你的工作是為本專案建立 **Local 層**
---
## 二、全域架構現況(已完成,勿修改)
`~/.claude/` 已包含:
| 路徑 | 內容 |
|------|------|
| `~/.claude/CLAUDE.md` | 全域憲法P7/P9/P10、三紅線、12-agent 委派表 |
| `~/.claude/settings.json` | 全域設定claude-sonnet-4-6 + 10 個 hooks |
| `~/.claude/hooks/` | 10 個 hookbranch-protection / commit-quality / python-quality / yaml-validator / large-file-warner / mcp-health / audit-log / suggest-compact / cost-tracker / session-summary |
| `~/.claude/agents/` | 10 個 agentcritic / debugger / planner / fullstack-engineer / refactor-specialist / migration-engineer / onboarder / tool-expert / vuln-verifier / web-researcher |
**全域 hooks 在本 session 已自動生效,無需重複安裝。**
---
## 三、hooks 合併規則(必讀)
Claude Code 的 hooks 採 **全域 + 專案 同時執行**(不覆蓋,疊加)。
因此:
- 全域 `commit-quality.js` 已掃描通用 secretOpenAI / GitHub / AWS / Anthropic
+ 讀取本專案的 `.claude/hooks/secrets.local.json` 補充專案專屬 pattern
- **本專案 settings.json 不需要再呼叫 commit-quality.js**(避免重複執行)
---
## 四、P7 執行計畫(六步,逐步完成)
### Step 1 — 讀取現況(禁止跳過)
執行以下指令,**全部讀完再開始動手**
```bash
# 1a. 確認全域架構
ls ~/.claude/hooks/
ls ~/.claude/agents/
# 1b. 讀取本專案現有 .claude/ 狀態
ls .claude/ 2>/dev/null || echo "無 .claude/ 目錄"
ls .claude/hooks/ 2>/dev/null
cat .claude/settings.json 2>/dev/null
# 1c. 讀取現有 CLAUDE.md
cat CLAUDE.md 2>/dev/null
# 1d. 確認分支策略
git log --oneline -5
git remote -v
```
---
### Step 2 — 建立 .claude/ 結構
```bash
mkdir -p .claude/hooks
mkdir -p .claude/agents
```
---
### Step 3 — 複製全域 agents
```bash
for f in ~/.claude/agents/*.md; do
name=$(basename "$f")
if [[ ! -f ".claude/agents/$name" ]]; then
cp "$f" ".claude/agents/$name"
echo "✅ agents/$name"
else
echo "⏭️ agents/$name 已存在,跳過"
fi
done
```
若本專案有**專案專屬 agent**(如 db-expert.md在此步驟後加入 `.claude/agents/`
---
### Step 4 — 建立三個設定檔
#### 4a. `.claude/hooks/branch-protection.local.json`
根據本專案分支策略選擇:
```bash
# 選項 Amain 可直接 commitpush-to-deploy 模式,如 momo
echo '{"protectedBranches": ["production"]}' > .claude/hooks/branch-protection.local.json
# 選項 Bmain 受保護,必須開 feature branch
echo '{"protectedBranches": ["main", "production"]}' > .claude/hooks/branch-protection.local.json
```
#### 4b. `.claude/hooks/secrets.local.json`
填入**本專案使用的 Token/Key 格式**,讓全域 commit-quality.js 自動載入:
```json
[
{"pattern": "PATTERN_REGEX", "label": "Token 名稱"},
{"pattern": "ANOTHER_PATTERN", "label": "另一個 Token"}
]
```
常見範例(按需選用):
```json
[
{"pattern": "\\d{8,12}:[A-Za-z0-9_-]{35}", "label": "Telegram Bot Token"},
{"pattern": "TELEGRAM[_\\s]*TOKEN\\s*=\\s*[\"']?[^\\s\"']{20,}", "label": "Telegram Token 環境變數"},
{"pattern": "glpat-[a-zA-Z0-9_-]{20}", "label": "Gitea/GitLab PAT"},
{"pattern": "GITEA[_\\s]*TOKEN\\s*=\\s*[\"']?[^\\s\"']{20,}", "label": "Gitea Token 環境變數"}
]
```
#### 4c. `.claude/settings.json`
**如果本專案已有 settings.json**:讀完後手動合併,保留現有欄位,只更新 hooks 格式。
**如果本專案沒有 settings.json**:直接建立:
```json
{
"permissions": {
"defaultMode": "bypassPermissions",
"additionalDirectories": ["/tmp"]
},
"hooks": {
"PreToolUse": [
{
"matcher": "",
"hooks": [
{"type": "command", "command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/<project>-guard.js"},
{"type": "command", "command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/large-file-warner.js"},
{"type": "command", "command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/mcp-health.js"}
]
}
],
"PostToolUse": [
{
"matcher": "",
"hooks": [
{"type": "command", "command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/audit-log.js"},
{"type": "command", "command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/suggest-compact.js"}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{"type": "command", "command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/cost-tracker.js"},
{"type": "command", "command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/session-summary.js"}
]
}
]
}
}
```
注意:
- `commit-quality.js` 不需列入(全域已跑)
- `<project>-guard.js` 是**本專案專屬的生產環境保護 hook**(見 Step 5
- `$CLAUDE_PROJECT_DIR` 是 Claude Code 自動注入的環境變數,指向專案根目錄
---
### Step 5 — 建立專案 guard hook
參考 momo-prod-guard.js為本專案寫一個 `<project>-guard.js`
**最小可用版本**(無任何阻擋,只稽核):
```javascript
// .claude/hooks/<project>-guard.js
const { spawnSync } = require('child_process');
let d = '';
process.stdin.on('data', c => d += c);
process.stdin.on('end', () => {
try {
const i = JSON.parse(d);
const cmd = String(i.tool_input?.command || '');
// 在此加入本專案需要阻擋的危險操作
// 參考: momo-prod-guard.js 的寫法
} catch (e) {}
process.stdout.write(d);
});
```
**需要阻擋的常見危險操作**(按本專案需求選用):
- `docker compose down -v`(刪 volume
- `kubectl delete namespace`
- `--remove-orphans`(如有多專案共存 Docker
- 直接操作 production DB
---
### Step 6 — 更新 CLAUDE.md
**保留**本專案現有的所有專案索引(環境、服務、指令等)。
**移除**與全域重複的通用規則P7/P9/P10、三紅線、委派表——這些由 `~/.claude/CLAUDE.md` 自動 concatenate 補全。
**在檔案頂部加入一行**
```markdown
> 全域工作流程P7/P9/P10、三紅線、委派表見 `~/.claude/CLAUDE.md`
```
**在檔案底部加入安全架構說明**
```markdown
## 安全架構bypassPermissions
本專案採用 `permissions.defaultMode: "bypassPermissions"` + Hook 自動政策。
| Hook | 觸發點 | 防護內容 |
|------|--------|---------|
| `<project>-guard.js` | PreToolUse | 專案危險操作阻擋 |
| `large-file-warner.js` | PreToolUse | >2MB 阻擋,>500KB 警告 |
| `mcp-health.js` | PreToolUse | MCP 冷卻保護 |
| `audit-log.js` | PostToolUse | Bash 指令稽核 |
| `suggest-compact.js` | PostToolUse | 50 次工具呼叫後建議 /compact |
| `cost-tracker.js` | Stop | Token 用量追蹤 |
| `session-summary.js` | Stop | 對話快照存檔 |
全域 Hook`~/.claude/hooks/`同時生效branch-protection / commit-quality / python-quality / yaml-validator
```
---
### Step 7 — 驗證 & commit
```bash
# 確認所有檔案就位
ls .claude/
ls .claude/hooks/
ls .claude/agents/
cat .claude/settings.json
# 確認 .gitignore 有排除 settings.local.json
grep "settings.local.json" .gitignore || echo ".claude/settings.local.json" >> .gitignore
# Commit
git add CLAUDE.md .claude/ .gitignore
git status # 最後確認一次
git commit -m "feat(claude): 套用 ty-ai-standards Global-Local 架構"
git push
```
---
## 五、完成後的架構圖
```
~/.claude/ ← 全域層(所有專案共用)
├── CLAUDE.md ← P7/P9/P10 + 三紅線 + 委派表
├── settings.json ← 全域 hooks 清單
├── hooks/ ← 10 個通用 hooks自動生效
└── agents/ ← 10 個通用 agents
<project>/.claude/ ← 本地層(本專案專屬)
├── settings.json ← bypassPermissions + 專案 hooks
├── agents/ ← 全域 agents 副本 + 專案特規 agent
└── hooks/
├── <project>-guard.js ← 專案危險操作保護
├── secrets.local.json ← 專案 Token pattern全域 commit-quality 自動載入)
└── branch-protection.local.json ← 分支保護覆蓋設定
```
---
## 六、判斷表:遇到衝突時
| 情況 | 做法 |
|------|------|
| 現有 settings.json 超大 | 讀清楚再合併,**不整個覆蓋** |
| 現有 hooks 已有 shell 版本 | 保留,並列執行;或改寫成 `.js` 統一管理 |
| CLAUDE.md 有大量專案規則 | **全部保留**,只加全域參照那一行,去掉通用重複段落 |
| 專案用 main 直接 push | `branch-protection.local.json``{"protectedBranches": ["production"]}` |
| 專案有 PR 審查流程 | `branch-protection.local.json``{"protectedBranches": ["main", "production"]}` |
| 現有 secret hook 已掃某 pattern | 不需加入 secrets.local.json避免雙重告警 |
---
## 七、完成判斷DoD
- [ ] `~/.claude/` 全域架構確認存在10 hooks + 10 agents
- [ ] `.claude/settings.json` 格式正確(`defaultMode: "bypassPermissions"` + 物件格式 hooks
- [ ] `.claude/hooks/secrets.local.json` 填入專案 Token pattern
- [ ] `.claude/hooks/branch-protection.local.json` 設定符合分支策略
- [ ] `.claude/agents/` 有 10 個通用 agents含專案特規 agent
- [ ] `CLAUDE.md` 加入全域參照、移除重複通用規則、加入安全架構說明
- [ ] `.gitignore``.claude/settings.local.json`
- [ ] Commit 成功push 成功

View File

@@ -2444,14 +2444,13 @@ def _generate_ppt_cmd(sub_type: str, sub_arg: str, _chat_id: int, target: str) -
return generate_promo_ppt(promo_label_p, data_p, ai_text_p)
elif sub_type in ('growth', '成長', '趨勢'):
# 檢查是否有快取的 PPT 報告
# Check for cached PPT report
from database.ppt_reports import PPTReport
from database.manager import get_session
from datetime import datetime, timedelta
session = get_session()
try:
# 查找今天是否有生成的成長趨勢報告
# Find today's generated growth trend report
today = datetime.now()
cached_report = session.query(PPTReport).filter(
PPTReport.report_type == 'growth',
@@ -2530,7 +2529,6 @@ def _generate_ppt_cmd(sub_type: str, sub_arg: str, _chat_id: int, target: str) -
# 檢查是否有快取的 PPT 報告
from database.ppt_reports import PPTReport
from database.manager import get_session
from datetime import datetime, timedelta
yr_v = now.year
mo_v = now.month
@@ -2542,7 +2540,7 @@ def _generate_ppt_cmd(sub_type: str, sub_arg: str, _chat_id: int, target: str) -
session = get_session()
try:
# 查找今天是否有生成的廠商報告
today = datetime.now()
today = now
cached_report = session.query(PPTReport).filter(
PPTReport.report_type == 'vendor',
PPTReport.parameters == f"{yr_v}/{mo_v:02d}",
@@ -2608,16 +2606,10 @@ def _generate_ppt_cmd(sub_type: str, sub_arg: str, _chat_id: int, target: str) -
except Exception as e:
sys_log.error(f"[OpenClawBot] 儲存廠商 PPT 快取失敗: {e}")
session.rollback()
finally:
session.close()
return ppt_path
elif sub_type in ('bcg', 'BCG', '品牌矩陣', '矩陣'):
# 檢查是否有快取的 PPT 報告
from database.ppt_reports import PPTReport
from database.manager import get_session
from datetime import datetime, timedelta
yr_b = now.year
mo_b = now.month

300
scripts/code_review.py Normal file
View File

@@ -0,0 +1,300 @@
#!/usr/bin/env python3
# ================= MOMO 系統 - Aider Code Review 自動化腳本 =================
# 功能:程式完成後自動觸發 Aider 進行 Code Review
# 作者AI Assistant
# 版本1.0
# =======================================================================
import argparse
import os
import subprocess
import sys
from datetime import datetime
from pathlib import Path
# 導入工具類
try:
from scripts.code_review_utils import CodeReviewLogger, CodeReviewConfig, CodeReviewValidator, GitHelper
except ImportError:
# 嘗試直接導入當在scripts目錄中執行時
try:
from code_review_utils import CodeReviewLogger, CodeReviewConfig, CodeReviewValidator, GitHelper
except ImportError:
print("❌ 無法導入工具類,請確保 code_review_utils.py 存在")
sys.exit(1)
class AiderCodeReview:
def __init__(self, project_root=None):
self.project_root = Path(project_root) if project_root else Path(__file__).parent.parent
# 初始化工具類
self.logger = CodeReviewLogger(self.project_root)
self.config = CodeReviewConfig(self.project_root)
self.validator = CodeReviewValidator()
self.git_helper = GitHelper(self.project_root)
# 檢查Git倉庫
if not self.git_helper.is_git_repository():
self.logger.warning("當前目錄不是Git倉庫某些功能可能無法使用")
# 檢查Aider路徑
self.aider_path = self.config.get("aider.path", "/Users/ooo/.local/bin/aider")
if not Path(self.aider_path).exists():
self.logger.error(f"Aider 路徑不存在: {self.aider_path}")
def log_review(self, message):
"""記錄Code Review日誌保持向後兼容"""
self.logger.info(message)
def get_changed_files(self, git_diff_filter="ACM"):
"""獲取Git中變更的檔案"""
try:
# 使用GitHelper獲取變更檔案
all_changed = self.git_helper.get_changed_files(
diff_filter=git_diff_filter,
use_staged=self.config.get("git.use_staged", True)
)
# 過滤允許的檔案類型
allowed_extensions = self.config.get("file_filters.allowed_extensions",
['.py', '.js', '.ts', '.jsx', '.tsx', '.html', '.css'])
filtered_files = []
for file_path in all_changed:
if any(file_path.endswith(ext) for ext in allowed_extensions):
# 檢查檔案是否存在且大小合理
abs_path = self.project_root / file_path
if abs_path.exists() and abs_path.is_file():
file_size = abs_path.stat().st_size
max_size = self.config.get("file_filters.max_file_size", 10485760)
if file_size <= max_size:
filtered_files.append(file_path)
else:
self.logger.warning(f"檔案過大,跳過: {file_path} ({file_size} bytes)")
else:
self.logger.warning(f"檔案不存在,跳過: {file_path}")
return filtered_files
except Exception as e:
self.logger.error("獲取變更檔案失敗", e)
return []
def run_aider_review(self, files=None, review_type="basic"):
"""執行Aider Code Review"""
if not files:
files = self.get_changed_files()
if not files:
self.log_review("📝 沒有需要Review的檔案")
return True
# 驗證Review類型
if not self.validator.validate_review_type(review_type):
self.logger.error(f"無效的Review類型: {review_type}")
return False
# 驗證檔案
valid_files = self.validator.validate_files(files, self.project_root)
if not valid_files:
self.logger.error("沒有有效的檔案可以Review")
return False
# 構建Aider命令
cmd = [self.aider_path]
# 從配置獲取Review類型對應的訊息
review_message = self.config.get(f"review_types.{review_type}.message")
if not review_message:
self.logger.error(f"找不到Review類型 {review_type} 的配置")
return False
# 添加Aider參數
if self.config.get("aider.auto_yes", False):
cmd.append("--yes")
if self.config.get("aider.no_git", True):
cmd.append("--no-git")
cmd.extend(["--message", review_message])
# 添加要review的檔案
cmd.extend(valid_files)
self.log_review(f"🔍 開始Code Review - 類型: {review_type}, 檔案: {', '.join(valid_files)}")
try:
# 設置環境變數
env = os.environ.copy()
env["PYTHONPATH"] = str(self.project_root)
# 執行Aider
timeout = self.config.get("aider.timeout", 600)
result = subprocess.run(
cmd,
cwd=self.project_root,
capture_output=True,
text=True,
env=env,
timeout=timeout
)
if result.returncode == 0:
self.log_review("✅ Code Review 完成")
# 保存Review結果
self.save_review_result(valid_files, result.stdout, review_type)
return True
else:
self.logger.error(f"Code Review 失敗: {result.stderr}")
return False
except subprocess.TimeoutExpired:
self.logger.error("Code Review 超時")
return False
except Exception as e:
self.logger.error("Code Review 異常", e)
return False
def save_review_result(self, files, output, review_type):
"""保存Review結果到檔案"""
try:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
safe_review_type = self.validator.sanitize_filename(review_type)
result_file = self.project_root / "logs" / f"review_{safe_review_type}_{timestamp}.md"
content = f"""# Code Review 報告
**時間**: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
**類型**: {review_type}
**檔案**: {', '.join(files)}
**Aider版本**: {self.aider_path}
## Review 結果
```
{output}
```
## 執行資訊
- **專案根目錄**: {self.project_root}
- **檔案數量**: {len(files)}
- **Review類型**: {review_type}
- **執行時間**: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
---
*由 Aider 自動生成 - MOMO 系統 Code Review*
"""
with open(result_file, "w", encoding="utf-8") as f:
f.write(content)
self.log_review(f"📄 Review結果已保存: {result_file}")
except Exception as e:
self.logger.error("保存Review結果失敗", e)
def review_specific_files(self, file_paths, review_type="basic"):
"""Review指定的檔案"""
try:
# 驗證Review類型
if not self.validator.validate_review_type(review_type):
self.logger.error(f"無效的Review類型: {review_type}")
return False
# 驗證並處理檔案路徑
valid_files = self.validator.validate_files(file_paths, self.project_root)
if not valid_files:
self.logger.error("沒有有效的檔案可以Review")
return False
return self.run_aider_review(valid_files, review_type)
except Exception as e:
self.logger.error("Review指定檔案失敗", e)
return False
def main():
try:
parser = argparse.ArgumentParser(
description="MOMO系統 Aider Code Review 自動化工具",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
使用範例:
%(prog)s --auto # 自動Review暫存檔案
%(prog)s --files app.py routes/*.py # Review指定檔案
%(prog)s --type security --auto # 安全檢查暫存檔案
%(prog)s --project-root /path/to/project # 指定專案根目錄
"""
)
parser.add_argument("--files", "-f", nargs="+",
help="指定要Review的檔案支援相對路徑和絕對路徑")
parser.add_argument("--type", "-t", choices=["basic", "security", "performance"],
default="basic", help="Review類型 (預設: basic)")
parser.add_argument("--project-root", "-p",
help="專案根目錄路徑(預設: 自動偵測)")
parser.add_argument("--auto", "-a", action="store_true",
help="自動Review暫存的檔案 (Git staged files)")
parser.add_argument("--verbose", "-v", action="store_true",
help="顯示詳細輸出")
parser.add_argument("--dry-run", action="store_true",
help="僅顯示將要Review的檔案不實際執行")
args = parser.parse_args()
# 初始化Code Review工具
reviewer = AiderCodeReview(args.project_root)
if args.verbose:
reviewer.logger.info(f"🔧 使用專案根目錄: {reviewer.project_root}")
reviewer.logger.info(f"🔧 Aider 路徑: {reviewer.aider_path}")
success = False
if args.dry_run:
# 乾運行模式
if args.auto:
files = reviewer.get_changed_files()
reviewer.logger.info(f"🔍 將Review的暫存檔案: {', '.join(files)}")
elif args.files:
valid_files = reviewer.validator.validate_files(args.files, reviewer.project_root)
reviewer.logger.info(f"🔍 將Review的指定檔案: {', '.join(valid_files)}")
else:
files = reviewer.get_changed_files()
reviewer.logger.info(f"🔍 將Review的變更檔案: {', '.join(files)}")
success = True
elif args.auto:
# 自動Review暫存的檔案
reviewer.logger.info("🚀 開始自動Review暫存檔案...")
success = reviewer.run_aider_review(review_type=args.type)
elif args.files:
# Review指定檔案
reviewer.logger.info(f"🚀 開始Review指定檔案: {', '.join(args.files)}")
success = reviewer.review_specific_files(args.files, args.type)
else:
# Review所有變更檔案
reviewer.logger.info("🚀 開始Review所有變更檔案...")
success = reviewer.run_aider_review(review_type=args.type)
if success:
reviewer.logger.info("✅ Code Review 流程完成")
sys.exit(0)
else:
reviewer.logger.error("❌ Code Review 流程失敗")
sys.exit(1)
except KeyboardInterrupt:
print("\n⚠️ 用戶中斷操作")
sys.exit(130)
except Exception as e:
print(f"❌ 程式執行錯誤: {e}")
if "--verbose" in sys.argv or "-v" in sys.argv:
import traceback
traceback.print_exc()
sys.exit(1)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,236 @@
#!/usr/bin/env python3
# ================= MOMO 系統 - Code Review 工具類 =================
# 功能提供Code Review相關的工具函數和錯誤處理
# 作者AI Assistant
# 版本1.0
# =======================================================================
import os
import sys
import json
import logging
import traceback
from datetime import datetime
from pathlib import Path
from typing import List, Dict, Any, Optional
class CodeReviewLogger:
"""Code Review 專用日誌記錄器"""
def __init__(self, project_root):
self.project_root = Path(project_root) if not isinstance(project_root, Path) else project_root
self.log_dir = self.project_root / "logs"
self.log_file = self.log_dir / "code_review.log"
# 確保日誌目錄存在
self.log_dir.mkdir(exist_ok=True)
# 設置日誌記錄器
self.logger = logging.getLogger("code_review")
self.logger.setLevel(logging.INFO)
# 避免重複添加handler
if not self.logger.handlers:
# 檔案handler
file_handler = logging.FileHandler(self.log_file, encoding='utf-8')
file_handler.setLevel(logging.INFO)
# 控制台handler
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
# 格式化器
formatter = logging.Formatter('[%(asctime)s] %(message)s', '%Y-%m-%d %H:%M:%S')
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)
self.logger.addHandler(file_handler)
self.logger.addHandler(console_handler)
def info(self, message: str):
"""記錄資訊日誌"""
self.logger.info(message)
def error(self, message: str, exception: Optional[Exception] = None):
"""記錄錯誤日誌"""
if exception:
self.logger.error(f"{message}: {str(exception)}")
self.logger.error(f"Traceback: {traceback.format_exc()}")
else:
self.logger.error(message)
def warning(self, message: str):
"""記錄警告日誌"""
self.logger.warning(message)
class CodeReviewConfig:
"""Code Review 配置管理"""
def __init__(self, project_root):
self.project_root = Path(project_root) if not isinstance(project_root, Path) else project_root
self.config_file = self.project_root / "config" / "code_review_config.json"
self.default_config = self._get_default_config()
self.config = self._load_config()
def _get_default_config(self) -> Dict[str, Any]:
"""獲取預設配置"""
return {
"aider": {
"path": "/Users/ooo/.local/bin/aider",
"timeout": 600,
"auto_yes": False,
"no_git": True
},
"review_types": {
"basic": {
"message": "請對這些檔案進行Code Review檢查\n1. 程式碼品質與最佳實踐\n2. 潛在的bug與安全問題\n3. 程式碼可讀性與維護性\n4. 效能優化建議"
},
"security": {
"message": "請重點檢查這些檔案的安全性:\n1. SQL注入風險\n2. XSS攻擊風險\n3. 認證與授權問題\n4. 敏感資料洩露風險\n5. 輸入驗證不足"
},
"performance": {
"message": "請分析這些檔案的效能問題:\n1. 演算法效率\n2. 資料庫查詢優化\n3. 記憶體使用\n4. 並發處理\n5. 快取策略"
}
},
"file_filters": {
"allowed_extensions": [".py", ".js", ".ts", ".jsx", ".tsx", ".html", ".css"],
"excluded_dirs": [".git", "__pycache__", "node_modules", "venv", "env", ".pytest_cache"],
"max_file_size": 10485760 # 10MB
},
"git": {
"diff_filter": "ACM", # Added, Copied, Modified
"use_staged": True
}
}
def _load_config(self) -> Dict[str, Any]:
"""載入配置檔案"""
if self.config_file.exists():
try:
with open(self.config_file, 'r', encoding='utf-8') as f:
user_config = json.load(f)
# 合併預設配置和用戶配置
return self._merge_config(self.default_config, user_config)
except Exception as e:
print(f"⚠️ 載入配置檔案失敗,使用預設配置: {e}")
return self.default_config
else:
# 創建預設配置檔案
self._save_config(self.default_config)
return self.default_config
def _merge_config(self, default: Dict, user: Dict) -> Dict:
"""合併配置"""
result = default.copy()
for key, value in user.items():
if key in result and isinstance(result[key], dict) and isinstance(value, dict):
result[key] = self._merge_config(result[key], value)
else:
result[key] = value
return result
def _save_config(self, config: Dict[str, Any]):
"""保存配置檔案"""
try:
self.config_file.parent.mkdir(exist_ok=True)
with open(self.config_file, 'w', encoding='utf-8') as f:
json.dump(config, f, indent=2, ensure_ascii=False)
except Exception as e:
print(f"⚠️ 保存配置檔案失敗: {e}")
def get(self, key_path: str, default=None):
"""獲取配置值"""
keys = key_path.split('.')
value = self.config
for key in keys:
if isinstance(value, dict) and key in value:
value = value[key]
else:
return default
return value
class CodeReviewValidator:
"""Code Review 資料驗證器"""
@staticmethod
def validate_files(files: List[str], project_root: Path) -> List[str]:
"""驗證檔案列表"""
valid_files = []
for file_path in files:
abs_path = project_root / file_path if not Path(file_path).is_absolute() else Path(file_path)
if not abs_path.exists():
print(f"⚠️ 檔案不存在: {file_path}")
continue
if not abs_path.is_file():
print(f"⚠️ 不是檔案: {file_path}")
continue
# 檢查檔案大小
if abs_path.stat().st_size > 10485760: # 10MB
print(f"⚠️ 檔案過大: {file_path}")
continue
valid_files.append(str(abs_path.relative_to(project_root)))
return valid_files
@staticmethod
def validate_review_type(review_type: str) -> bool:
"""驗證Review類型"""
return review_type in ["basic", "security", "performance"]
@staticmethod
def sanitize_filename(filename: str) -> str:
"""清理檔案名稱"""
# 移除危險字符
dangerous_chars = ['..', '/', '\\', ':', '*', '?', '"', '<', '>', '|']
for char in dangerous_chars:
filename = filename.replace(char, '_')
return filename
class GitHelper:
"""Git 操作輔助工具"""
def __init__(self, project_root: Path):
self.project_root = project_root
def get_changed_files(self, diff_filter: str = "ACM", use_staged: bool = True) -> List[str]:
"""獲取變更的檔案"""
try:
cmd = ["git"]
if use_staged:
cmd.extend(["diff", "--cached", "--name-only", "--diff-filter", diff_filter])
else:
cmd.extend(["diff", "--name-only", "--diff-filter", diff_filter])
result = subprocess.run(
cmd,
cwd=self.project_root,
capture_output=True,
text=True,
timeout=30
)
if result.returncode == 0:
files = [f.strip() for f in result.stdout.split('\n') if f.strip()]
return files
else:
print(f"❌ Git 命令失敗: {result.stderr}")
return []
except subprocess.TimeoutExpired:
print("❌ Git 命令超時")
return []
except Exception as e:
print(f"❌ Git 操作異常: {e}")
return []
def is_git_repository(self) -> bool:
"""檢查是否為Git倉庫"""
git_dir = self.project_root / ".git"
return git_dir.exists() and git_dir.is_dir()
# 導入subprocess用於GitHelper
import subprocess

100
scripts/quick_review.sh Executable file
View File

@@ -0,0 +1,100 @@
#!/bin/bash
# ================= MOMO 系統 - 快速 Code Review 腳本 =================
# 功能:快速觸發 Aider Code Review
# 使用方法:./quick_review.sh [檔案名稱...]
# 範例:./quick_review.sh app.py routes/sales_routes.py
# =======================================================================
# 顏色定義
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 獲取專案根目錄
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CODE_REVIEW_SCRIPT="$PROJECT_ROOT/scripts/code_review.py"
# 顯示標題
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}🔍 MOMO 系統 - Aider Code Review${NC}"
echo -e "${BLUE}========================================${NC}"
# 檢查Code Review腳本是否存在
if [ ! -f "$CODE_REVIEW_SCRIPT" ]; then
echo -e "${RED}❌ Code Review腳本不存在: $CODE_REVIEW_SCRIPT${NC}"
exit 1
fi
# 檢查Python環境
if ! command -v python3 &> /dev/null; then
echo -e "${RED}❌ Python3未安裝${NC}"
exit 1
fi
# 檢查Aider
if ! command -v aider &> /dev/null; then
echo -e "${RED}❌ Aider未安裝或不在PATH中${NC}"
exit 1
fi
# 顯示選單
if [ $# -eq 0 ]; then
echo -e "${YELLOW}請選擇操作:${NC}"
echo "1) 自動Review暫存檔案 (Git staged)"
echo "2) Review所有變更檔案"
echo "3) 指定檔案Review"
echo "4) 安全檢查 (Security Review)"
echo "5) 效能檢查 (Performance Review)"
echo ""
read -p "請輸入選項 (1-5): " choice
case $choice in
1)
echo -e "${GREEN}🚀 開始自動Review暫存檔案...${NC}"
python3 "$CODE_REVIEW_SCRIPT" --auto --type basic
;;
2)
echo -e "${GREEN}🚀 開始Review所有變更檔案...${NC}"
python3 "$CODE_REVIEW_SCRIPT" --type basic
;;
3)
echo -e "${YELLOW}請輸入要Review的檔案路徑 (用空格分隔)${NC}"
read -r files_input
if [ -n "$files_input" ]; then
echo -e "${GREEN}🚀 開始Review指定檔案...${NC}"
python3 "$CODE_REVIEW_SCRIPT" --files $files_input --type basic
else
echo -e "${RED}❌ 未指定檔案${NC}"
exit 1
fi
;;
4)
echo -e "${GREEN}🛡️ 開始安全檢查...${NC}"
python3 "$CODE_REVIEW_SCRIPT" --auto --type security
;;
5)
echo -e "${GREEN}⚡ 開始效能檢查...${NC}"
python3 "$CODE_REVIEW_SCRIPT" --auto --type performance
;;
*)
echo -e "${RED}❌ 無效選項${NC}"
exit 1
;;
esac
else
# 有指定檔案直接Review
echo -e "${GREEN}🚀 開始Review指定檔案...${NC}"
echo -e "${BLUE}檔案:$@${NC}"
python3 "$CODE_REVIEW_SCRIPT" --files "$@" --type basic
fi
# 檢查執行結果
if [ $? -eq 0 ]; then
echo -e "${GREEN}✅ Code Review 完成!${NC}"
echo -e "${BLUE}📄 Review報告位置$PROJECT_ROOT/logs/${NC}"
else
echo -e "${RED}❌ Code Review 失敗!${NC}"
exit 1
fi

View File

@@ -0,0 +1,246 @@
#!/bin/bash
# =============================================================================
# MOMO Pro System - External Access Fix Script
# Purpose: Fix external network access issues for mo.wooo.work
# Problem: Some external networks cannot access the web service
# Solution: Update firewall rules to allow broader web access
# Date: 2026-04-22
# =============================================================================
set -e
# Configuration
UAT_IP="114.32.151.246" # This is the actual server IP
GCP_IP="35.194.233.141"
GCP_PROJECT="astral-gateway-484913-d7"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Logging functions
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# =============================================================================
# Main Fix Functions
# =============================================================================
fix_nginx_configuration() {
log_info "Updating Nginx configuration for external access..."
# Create updated nginx config that allows all external access
cat > /tmp/momo-nginx-fix.conf << 'EOF'
server {
listen 80;
server_name mo.wooo.work momo.wooo.work;
# Redirect HTTP to HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name mo.wooo.work momo.wooo.work;
# SSL certificates (Let's Encrypt)
ssl_certificate /etc/letsencrypt/live/mo.wooo.work/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mo.wooo.work/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Upload size limit
client_max_body_size 50M;
# Logs
access_log /var/log/nginx/momo_access.log;
error_log /var/log/nginx/momo_error.log;
# Main application proxy
location / {
proxy_pass http://127.0.0.1:5003;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Timeout settings
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# Buffer settings for large responses
proxy_buffers 8 32k;
proxy_buffer_size 64k;
}
# Health check endpoint
location /health {
access_log off;
proxy_pass http://127.0.0.1:5003/health;
proxy_set_header Host $host;
}
# Static files (if any)
location /static/ {
alias /app/static/;
expires 1y;
add_header Cache-Control "public, immutable";
}
}
EOF
log_info "Nginx configuration template created"
}
update_firewall_rules() {
log_info "Updating firewall rules for external web access..."
# UFW Firewall updates (if this is the actual server)
if [[ "$(hostname -I | grep -o '114\.32\.151\.246')" ]]; then
log_info "Detected UAT server, updating UFW rules..."
# Allow HTTP/HTTPS from anywhere
sudo ufw allow 80/tcp comment 'HTTP from anywhere'
sudo ufw allow 443/tcp comment 'HTTPS from anywhere'
# Ensure web server can accept connections
sudo ufw allow from 0.0.0.0/0 to any port 80,443 proto tcp comment 'Web services'
log_info "UFW firewall rules updated"
else
log_warn "Not running on UAT server. Manual firewall update may be needed."
fi
}
# GCP firewall function removed - focusing on local environment only
check_external_connectivity() {
log_info "Testing external connectivity..."
# Test from different perspectives
local domains=("mo.wooo.work" "momo.wooo.work")
for domain in "${domains[@]}"; do
log_info "Testing $domain..."
# DNS resolution
if nslookup $domain > /dev/null 2>&1; then
local ip=$(nslookup $domain | grep -A1 "Name:" | tail -1 | awk '{print $2}')
log_info " DNS: $domain -> $ip"
else
log_error " DNS: Failed to resolve $domain"
fi
# HTTP connectivity
if curl -s --connect-timeout 10 "http://$domain" | head -1 > /dev/null 2>&1; then
log_info " HTTP: Connection successful"
else
log_warn " HTTP: Connection failed or redirected"
fi
# HTTPS connectivity
if curl -s --connect-timeout 10 "https://$domain" | head -1 > /dev/null 2>&1; then
log_info " HTTPS: Connection successful"
else
log_error " HTTPS: Connection failed"
fi
done
}
restart_services() {
log_info "Restarting services..."
# Restart nginx if it exists
if command -v nginx > /dev/null 2>&1; then
sudo nginx -t && sudo systemctl reload nginx || sudo systemctl restart nginx
log_info "Nginx restarted"
fi
# Restart docker services if using docker
if command -v docker > /dev/null 2>&1; then
if docker ps | grep momo-app > /dev/null 2>&1; then
docker restart momo-pro-system 2>/dev/null || true
log_info "Docker services restarted"
fi
fi
}
# =============================================================================
# Main Execution
# =============================================================================
main() {
echo ""
echo "${GREEN}============================================================================${NC}"
echo "${GREEN} MOMO Pro System - External Access Fix Tool${NC}"
echo "${GREEN}============================================================================${NC}"
echo ""
log_info "Starting external access fix for mo.wooo.work..."
echo ""
# Step 1: Update configurations
log_info "Step 1: Updating configurations..."
fix_nginx_configuration
# Step 2: Update firewall rules
echo ""
log_info "Step 2: Updating firewall rules..."
update_firewall_rules
# Step 3: Skip GCP firewall (local environment only)
echo ""
log_info "Step 3: Skipping GCP firewall (local environment only)..."
# Step 4: Restart services
echo ""
log_info "Step 4: Restarting services..."
restart_services
# Step 5: Test connectivity
echo ""
log_info "Step 5: Testing external connectivity..."
check_external_connectivity
echo ""
log_info "External access fix completed!"
echo ""
echo "${YELLOW}Next steps:${NC}"
echo "1. Verify https://mo.wooo.work is accessible from different networks"
echo "2. Check SSL certificate validity"
echo "3. Monitor application logs for any issues"
echo "4. Test from mobile networks and different ISPs"
echo ""
if [[ -f /tmp/momo-nginx-fix.conf ]]; then
echo "${GREEN}Nginx configuration template created at: /tmp/momo-nginx-fix.conf${NC}"
echo "Please manually apply this configuration if needed."
fi
}
# Run main function
main "$@"

View File

@@ -10,10 +10,10 @@
# 白名單 IP 定義
# ============================================
# UAT 主機 IP (內網)
UAT_IP="192.168.0.110"
# UAT IP (UAT VM IP - actual server IP)
UAT_IP="114.32.151.246"
# GCP 主機 IP (外網)
# GCP IP (GCP VM IP)
GCP_IP="35.194.233.141"
# 辦公室/家庭 IP (需要能訪問監控服務的 IP)
@@ -21,6 +21,12 @@ GCP_IP="35.194.233.141"
ALLOWED_EXTERNAL_IPS=(
"114.32.151.246" # WOOO 辦公室 IP (範例)
"1.160.0.0/16" # 中華電信 ADSL 範圍 (範例)
"192.168.1.0/24" # 新增家庭網路範圍
"10.0.0.0/8" # 新增內網範圍
"172.16.0.0/12" # 新增內網範圍
"192.168.0.0/16" # 新增家庭網路範圍
"10.10.0.0/16" # 新增內網範圍
"172.20.0.0/14" # 新增內網範圍
)
# GCP 專案資訊

1
templates/components Symbolic link
View File

@@ -0,0 +1 @@
../web/templates/components