Files
pokemon-radar-api/CLAUDE.md
Timmy f7ef105436 init: Redis-backed Pokémon 雷達 API
- radar_fetcher.py:呼叫 Function Server 抓 twpkinfo.com 資料後寫入 Redis (TTL 300s)
- pokemon_radar_api.py:FastAPI /scan,從 Redis 讀取並依 request 即時二次篩選;Redis 不可用時回 200 空結果,不再 500
- pokemon_location_fetcher.py:舊版 CLI,仍由 fetch_and_upload.sh 使用
- 文件:README (參考手冊)、QUICKSTART (操作指南)、SUMMARY (故事線)、CLAUDE.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 09:13:59 +08:00

71 lines
4.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## 常用指令
套件管理使用 `uv`(見 `pyproject.toml``uv.lock``.python-version` = 3.12)。所有 Python 進入點都透過 `uv run` 執行。
- **啟動 API**`./run_pokemon_radar_api.sh`(內含 `uv run uvicorn pokemon_radar_api:app --host 0.0.0.0 --port 8008 --log-config logging.ini`
- **執行新版 fetcher寫入 Redis**`uv run python radar_fetcher.py`
- **執行舊版 fetcher產生本地 JSON/CSV/截圖)**`uv run python pokemon_location_fetcher.py --script twpk_radar.mjs --lat 25.0478 --lng 121.5170 --zoom 16 --state state.json --ua-from-state --min-remaining 300 --min-iv 90`
- **檢視 Redis 快取內容**`uv run python reader.py`rich 表格)或 `uv run python check_redis.py`raw JSON dump
- **生產環境排程腳本**`./fetch_and_upload.sh`(使用 `flock` 鎖定 `/var/lock/poke_radar.lock`;呼叫**舊版** `pokemon_location_fetcher.py`,然後 `scp``192.168.42.104:/opt/caddy/www/pokemon/spots.json`
本專案沒有測試、linter、build 流程。
## 架構
這是一個兩階段的 pipeline被一個 FastAPI 即時查詢層所包裝。有**兩條共存的 fetch pipeline**,修改時務必了解各自的用途:
### 資料流
```
twpkinfo.com (ipoke.aspx)
│ browser automation (Puppeteer)
Function Server (192.168.42.124:13000/function)
│ POST {code: <injected twpk_radar.mjs>}, 150s timeout
┌─────┴─────────────────────────────┐
│ │
│ (Pipeline A寫入 Redis) │ (Pipeline B寫入本地檔)
│ radar_fetcher.py │ pokemon_location_fetcher.py (CLI)
│ └─→ Redis SETEX │ └─→ pokemon_data.{json,csv}
│ pokemon:radar:latest │ + screenshot.png
│ TTL 300s │
└─────┬─────────────────────────────┘
pokemon_radar_api.py (FastAPI, :8008)
POST /scan → 即時篩選 Redis 內容回傳
```
### 關鍵設計
- **`twpk_radar.mjs` 是 Function Server 上跑的 worker**不是本地執行的模組。Python 端透過 regex 在字串層級注入變數,這個契約不能壞:
- `const TARGET = {...};` → 由 `_inject_target_and_shot` 覆寫
- `const DO_SCREENSHOT = true|false;` → 同上
- `globalThis.__POKE_STATE__` → 由 `_inject_state` 前置插入(含 cookies/localStorage/UA/langs
- 修 MJS 時,上述 3 個錨點的形狀必須維持,否則 regex 會失效
- **`pokemon_radar_api.py` 重用舊 client 的 `postprocess` 方法**,但**不**透過它去抓資料:`_filter_helper = PokemonRadarClient(url="", token="")`。Redis 存的是已篩選過一次(由 fetcher但仍保留較寬原始集的資料API 再依 request 參數做即時二次篩選(`min_remaining` / `min_iv` / `perfect_only` / `species`)。`ScanRequest` 裡的 `lat/lng/zoom/shot/...` 欄位在 Redis 模式下是**忽略的**,純粹保留給前端/n8n 相容。
- **兩個 fetcher 的篩選邏輯重複實作了兩次**`radar_fetcher._postprocess``PokemonRadarClient.postprocess`),修改篩選規則時要同步兩邊。
- **`fetch_and_upload.sh` 目前走的是 Pipeline B本地檔 + scp不是 Pipeline ARedis**。這是生產環境仍在使用的路徑;若改 fetcher 行為要確認影響哪一邊。
### 設定
- `.env`(本地)驅動 `radar_fetcher.py``pokemon_radar_api.py``reader.py``check_redis.py`。注意 `radar_fetcher.py` 預設 `REDIS_HOST=localhost`,但 API / reader / `.env``192.168.42.211` — fetcher 跑在 Redis 本機、API 跑遠端。
- `state.json` 是使用者登入後的 cookies/localStorage/UA 快照;用於繞過 twpkinfo.com 的人機驗證。過期時整條 pipeline 會靜默產 0 筆。`radar_fetcher._postprocess` 有一個診斷:當 `raw_items` 非空但篩完為 0 時會 log remaining/perfect 的分佈,優先看這個。
- `FUNCTION_TOKEN` 必填radar_fetcher 會直接 raise舊 CLI 則有 hard-coded default `6R0W53R135510`
## 專案慣例
- 全專案以**繁體中文(台灣用語)**溝通與註解。
- log 訊息不要使用 emoji現存檔案中的 emoji 是歷史遺留,新寫或修改時改成純文字。
- repo 根目錄的 `*_BACKUP_YYYYMMDDHHMMSS` 檔案是舊備份,可以清掉。