vecyang1/place-intel

GitHub: vecyang1/place-intel

利用 AI 自动抓取并分析 Google Maps 地点的完整评价历史,生成价格情报和风险预警报告,帮助用户在进店前充分了解商家。

Stars: 0 | Forks: 0

# placeintel — 有备而来 🎯 进店之前,先读完它的几百条评价。从此不再毫无准备地被报出“游客价”。 只需说出 *"会安 吉他租赁"* —— 使用**任意语言** —— AI 便会自动规划搜索任务: 将其翻译为双语 Google Maps 查询,提取位置,选择对应的 报告配置,发现地点,**附带明确理由过滤掉不在范围内的垃圾信息** (在搜索吉他时不会再出现摩托车租赁结果),抓取**完整的评价** 历史(数百条评价 —— 官方 API 限制最多仅 5 条),将所有内容在本地缓存,对评价进行 embedding 以实现语义搜索,最后让 Gemini 推理出一份情报 报告:**价格情报 · 硬信息核实 · 红旗预警 · 30 秒进店简报**。 ## 安装 ``` git clone https://github.com/vecyang1/place-intel.git cd place-intel python -m venv .venv && source .venv/bin/activate pip install -e ".[web]" # add the web app; use `pip install -e .` for CLI-only # 审查 scraper(单独 vendored,MIT 许可证)以保持此 repo 精简: git clone https://github.com/georgekhananaev/google-reviews-scraper-pro.git \ vendor/google-reviews-scraper-pro cp .env.example .env # then add at least one Gemini key ``` ## 快速开始 ``` .venv/bin/placeintel scout "会安 吉他租赁" # AI plans everything .venv/bin/placeintel shop "D'Class Guitar" --near "Hoi An" # ONE shop (name or Maps URL) .venv/bin/placeintel ask "哪家有耐心的老师?" # RAG over everything cached .venv/bin/placeintel plan "在岘港学冲浪" # debug: see the AI's plan .venv/bin/placeintel-web # web app → http://127.0.0.1:9618 ``` Web 应用会开启一个指挥中心式的 Scout 输入界面:粘贴 Maps URL,输入店铺 名称,基于缓存证据提问,或者描述一个宽泛的需求,它会在提交前推荐你使用 Scout、Shop 或 Ask 模式。四个视图依然保留:**侦察 Scout**(自由 文本输入 + 实时进度时间线,以及展示 AI 计划、过滤 结论、深度调研的店铺、重试/缓存组和 Compare 选择的最终结果),**单店 Shop** (单个名称/URL → 聚焦档案),**资料库 Library** (缓存店铺 + 历史搜索 → 包含报告、范围限定提问、评价 浏览器的店铺档案),**提问 Ask**(跨店 RAG + 所有历史提问,包括 按店铺标记的店铺范围限定提问)。 ## 本地验证 ``` .venv/bin/python -m unittest discover -s tests -p 'test_*.py' -v npm install npm run test:web # requires the local web app on http://127.0.0.1:9618 .venv/bin/placeintel doctor --json ``` Agent 和运维契约: - HTTP API:[`docs/API.md`](docs/API.md) - Agent CLI:[`docs/agent-cli.md`](docs/agent-cli.md) - 运维手册:[`docs/operations.md`](docs/operations.md) ## 私有部署 私有部署路径为 GitHub Actions → SSH → 原生 systemd 服务。 除非位于明确的受保护代理之后,否则 FastAPI 应用应保持在 loopback (`127.0.0.1:9618`)。 所需的私有仓库 secrets 在此公开 README 中使用了占位符名称: ``` PLACEINTEL_DEPLOY_HOST PLACEINTEL_DEPLOY_USER PLACEINTEL_DEPLOY_PORT PLACEINTEL_DEPLOY_SSH_KEY PLACEINTEL_DEPLOY_DIR GOOGLE_API_KEY VECTORENGINE_API_KEY SERPAPI_API_KEY PLACEINTEL_REASON_MODEL ``` 部署后,通过 SSH 隧道或经过身份验证的内部 URL 进行验证: ``` ssh -fN -L 9619:127.0.0.1:9618 EXPECTED_VERSION=$(.venv/bin/python -c "import placeintel; print(placeintel.__version__)") .venv/bin/placeintel deploy-smoke \ --base-url "http://127.0.0.1:9619" \ --expected-version "$EXPECTED_VERSION" \ --format json ``` 对于受保护的公共域名,请将真实的 URL 和 Basic Auth 值保留在本地的 gitignored 文件或部署 secrets 中。公共安全的身份验证检查如下: ``` EXPECTED_VERSION=$(.venv/bin/python -c "import placeintel; print(placeintel.__version__)") .venv/bin/placeintel deploy-smoke \ --base-url "http://127.0.0.1:9619" \ --public-url "https://PLACEHOLDER_PROTECTED_DOMAIN" \ --expected-version "$EXPECTED_VERSION" \ --format json ``` 完整的部署冒烟测试、备份、还原和回滚手册请参见 [`docs/operations.md`](docs/operations.md)。 ## 工作原理 ``` free text ─► planner.py ──── AI plan: intent, bilingual queries, location, profile, │ discover-vs-single mode (fail-open: raw passthrough) ▼ discover.py ──────── gosom/google-maps-scraper (Docker, free) │ └ fallback: SerpAPI google_maps ▼ planner.filter ───── AI relevance verdicts per candidate (fail-open: keep all) ▼ reviews.py ────────── vendor/google-reviews-scraper-pro (Selenium, incremental) │ └ fallback: SerpAPI google_maps_reviews ▼ cache.py ──────────── data/placeintel.db (SQLite: places/reviews/reports/vectors) │ embed.py ──────────── Gemini Embedding 2, Google official (768-dim, true batch) │ analyze.py ────────── Gemini Flash (VectorEngine) long-context over ALL reviews │ cli.py / server.py (events → live timeline) / web/ SPA / Claude skill ``` 重要的设计选择: - **AI 在各个环节均采用失败放行机制**:失效的 LLM 会降级为原始查询透传并 保留所有候选者 —— 它绝不会阻塞抓取 pipeline。 - **针对单个地点的报告采用推理而非检索**:某个地点的完整评价集可以放入 Flash 的上下文中,因此报告会读取*所有内容* —— 而 embedding 则用于在不断扩充的缓存上执行跨店 `ask` 查询。 - **缓存优先**:7 天内进行相同搜索 = 不重新发现;评价通过增量方式抓取;当没有 新评价产生时,报告将被**复用**。 - **提供商划分**(由用户决定):embedding → Google 官方(真正的 Content-list 批处理,64 个文档/2 秒);推理 → VectorEngine(相同的模型,价格更低)。 - **Profiles** (`profiles/*.yaml`):`_core.yaml`(价格/硬事实/红旗预警)会合并 到每一个 profile 中;添加一个 YAML 即可增加一个领域(课程、租赁等)。 - **透明度是一项功能**:每个阶段都会发出 `{t, stage, msg}` 事件,并 在 CLI 和 Web 端渲染为实时时间线 —— 包括*为什么*每家店铺会被排除。 ## 环境要求与密钥 - Docker(用于免费发现)—— 在 macOS 上自动启动;否则使用 `--force-serpapi` - Chrome(用于评价抓取器) - 通过 `.env` 或环境变量提供密钥(参见 `.env.example`):`GOOGLE_API_KEY` (AIza…,用于 embedding)、`VECTORENGINE_API_KEY` (sk-…,用于推理) 以及可选的 `SERPAPI_API_KEY`(后备方案)。至少需要一个 Gemini 密钥。 ## 踩坑经验(来之不易) - 两者提供商都会将普通的字符串列表 embed 输入**聚合为一个向量** —— 真正的 批处理需要显式的 `types.Content` 对象 (embed.py)。 - 推理 prompt 必须包含**今天的日期**,否则模型会将最近的评价标记为 “伪造的未来日期” (analyze.py)。 - 越南语音符会破坏简单的名称匹配 ("Hội An" ≠ "Hoi An") —— 请使用 `cache.norm_name` (NFD strip + đ→d + token-AND)。 - 必须在展开线程之前构造好 `genai.Client`。 - gosom 输出可能是 NDJSON 或 JSON 数组;reviews-scraper-pro 通过 `places.original_url` 进行映射;SeleniumBase 需要 9222 端口冲突引导 (reviews.py)。 ## 致谢 站在开源的肩膀上 —— 请给他们点个 ⭐: - [gosom/google-maps-scraper](https://github.com/gosom/google-maps-scraper) — 免费地点发现 (Docker) - [georgekhananaev/google-reviews-scraper-pro](https://github.com/georgekhananaev/google-reviews-scraper-pro) — 完整评价历史抓取 (MIT) - [Google Gemini](https://ai.google.dev/) — embedding + 推理 · [SerpAPI](https://serpapi.com) — 可选后备方案 ## 许可证 MIT — 详见 [LICENSE](LICENSE)。
标签:Gemini, RAG, URL抓取, 人工智能, 情报分析, 数据抓取, 用户模式Hook绕过, 网络诊断, 请求拦截, 逆向工具