内容
<p align="center">
<img src="src/stimmo/web/static/favicon-64.png" width="64" alt="stimmo logo" />
</p>
# stimmo


**这真的是米兰的好价格吗?**
stimmo 检查任何米兰公寓的要价是否与其所在区域、房产类型和状况的官方 OMI €/m² 波段相符,同时考虑到楼层、电梯、能源等级、户外空间等。你会得到一个结论:**低估**、**合理** 或 **高估**。
没有机器学习,没有黑盒。每个乘数都是[一个公共系数文件](src/stimmo/valuation/adjustments.py)中的一个数字。

## 快速开始
```sh
uv sync
uv run stimmo-web # → http://127.0.0.1:8000
```
填写列表的地址、面积、状况和要价。stimmo 会对地址进行地理编码,查找 OMI 区域,运行调整并返回结论,同时提供完整的明细和该区域的 8 个学期价格趋势。
可以通过环境变量 `STIMMO_HOST` / `STIMMO_PORT` 重写绑定地址。
## 工作原理
- **OMI 波段** — 来自 *Agenzia delle Entrate* 的官方 €/m² 最小-最大值,按区域 × 房产类型 × 状况划分,来源于米兰市开放数据门户。
- **调整** — 一个小型、完全透明的乘数表(楼层、电梯、精细状况、能源等级、户外空间、停车位、设施)。没有机器学习;整个调整表面都在 [`valuation/adjustments.py`](src/stimmo/valuation/adjustments.py) 中。
- **设施评分** — 通过 OpenStreetMap Overpass 统计附近的兴趣点。
- **结论** — 要价与调整后的波段比较,±5% 容差。
> ⚠️ 意大利的成交价格数据不公开。OMI `Compr_min`–`Compr_max` 波段是估算的基础;乘数调整它但不取代它。
## 架构
- `src/stimmo/data/` — 捆绑的 OMI 报价、区域多边形和历史 CSV;实时调用 Nominatim 和 Overpass。
- `src/stimmo/valuation/` — 估算流程:调整(单个调整表面)、引擎和结论分类器。
- `src/stimmo/web/` — FastAPI 应用和 Jinja 模板;`stimmo-web` 入口点。
- `src/stimmo/mcp/` — MCP 服务器,通过 Streamable HTTP 公开估算流程(挂载在 `/mcp`)。
- `scripts/` — 数据刷新工具(从 CKAN API 拉取最新的 OMI 资产)。
- `tests/` — pytest 套件。
## 连接 Claude
stimmo 在 **`https://stimmo.it/mcp`** (Streamable HTTP,无认证,按 IP 限速)上支持 [模型上下文协议](https://modelcontextprotocol.io)。将以下内容添加到您的 Claude Desktop 或 Claude Code 配置中:
```json
{
"mcpServers": {
"stimmo": { "type": "http", "url": "https://stimmo.it/mcp" }
}
}
```
工具:`estimate_property`, `lookup_omi_quote`, `geocode_milan_address`, `omi_zone_for_point`, `amenity_score`, `omi_history`. 有关完整的表面、资源、提示和速率限制层的信息,请参见 [docs/mcp-server.md](docs/mcp-server.md)。
## 分享估算结果
每个估算结果都有一个 **分享 ↗** 按钮,生成一个自包含的链接 (`/{lang}/s/{token}`),重新渲染完整的结果,以及每个估算结果的 Open Graph 卡片 (`/og/{token}.png`),以便在社交应用中展开链接。估算结果编码在 URL 中 — 无需数据存储 — 并在打开时根据当前数据重新计算。参见 [docs/sharing-estimates.md](docs/sharing-estimates.md)。
## 刷新数据
OMI 学期资产(销售 €/m² + 区域多边形)捆绑在 `src/stimmo/data/assets/` 中。要从 `dati.comune.milano.it` 拉取最新学期:
```sh
uv run python scripts/refresh_omi.py
```
脚本通过 CKAN API 发现最新的 "Compravendita" + "Zone e Perimetri" 数据集,并原地重写两个文件。如果学期更新,请在 `src/stimmo/data/omi.py` 中增加 `SEMESTER` 常量。
## "近期成交价格"
意大利不发布每笔交易的价格数据。最近的免费代理是 **OMI €/m² 学期波段**,它本身源自观察到的销售数据。捆绑的 `milano_omi_history.csv` 包含过去 8 个学期的 MILANO Compravendita 报价;报告显示匹配的区域+类型+状况,并带有学期差异和整体趋势。
## 注意事项
- 多边形覆盖范围仅限米兰市 — 大都市区(Sesto San Giovanni, Cinisello 等)的地址将失败,显示为“outside Milano”。
- 没有实时的可比列表;波段来自 OMI 最小/最大值,而不是拟合模型。这是设计如此。
- 结论将要价与移位后的波段(OMI rogito + 6%)比较。有关理由,请参见 `/about`。
## 测试
```sh
uv run pytest
```
## 数据源
- OMI Compravendita per semestre(Comune di Milano,CKAN):
[dati.comune.milano.it — quotazioni OMI compravendita](https://dati.comune.milano.it/dataset/?q=quotazioni+immobiliari+OMI+compravendita)
- OMI Zone e Perimetri(Comune di Milano,CKAN):
[dati.comune.milano.it — zone e perimetri OMI](https://dati.comune.milano.it/dataset/?q=zone+e+perimetri+omi)
- Nominatim: [nominatim.openstreetmap.org](https://nominatim.openstreetmap.org/)
- Overpass: [overpass-api.de](https://overpass-api.de/)
## 许可证
代码:Apache-2.0(参见 [LICENSE](LICENSE))。
捆绑数据:OMI 报价和区域多边形根据 IODL 2.0(意大利开放数据许可证)从 Comune di Milano CKAN 门户重新分发 — 需要署名。
实时数据:OpenStreetMap(Nominatim,Overpass)根据 ODbL — 需要署名用于任何渲染输出。
## AI 辅助开发
该项目在 Claude Code 的帮助下开发。有关提供给 AI 助手的项目上下文,请参见 [CLAUDE.md](CLAUDE.md);会话特定的代理工件(`.claude/plans/`、`.claude/reports/`、`.claude/settings.local.json`)被 gitignore — 只有 `CLAUDE.md` 和共享代理配置被版本控制。
## 免责声明
stimmo 是一个公平性检查,而不是官方评估(perizia)。它不能取代合格的专业估价(perito),不应作为法律、财政或合同决定的依据。