# Sentinel Lens API 文档 Base URL: `http://crawler-api.aitoolcore.com` --- ## 认证 ### POST /api/auth/login 登录获取 JWT Token。 **Request Body** ```json { "username": "admin", "password": "admin123" } ``` **Response 200** ```json { "access_token": "eyJ...", "token_type": "bearer" } ``` **Response 401** — 用户名或密码错误 --- ## 公开价格接口 ### GET /api/public/prices 获取价格快照数据。调用时会自动记录来源 IP 和 Referer,并根据域名匹配折扣。 > 数据来源为 `price_snapshot` 表,仅在爬取结果与上次不同时才更新,版本号同步自增。 **Headers(必填)** | Header | 说明 | |---------|--------------------------------------------------------------------------------------| | Referer | 调用方来源域名,缺少返回 400 | | version | 客户端持有的版本号(整数)。不传或传 `0` 视为首次请求,强制返回数据;与服务端一致时返回 `up_to_date: true` | **Query Parameters** | 参数 | 类型 | 默认值 | 说明 | |------|--------|--------|---------------------------| | url | string | — | 指定单个模型页面 URL 过滤 | **Response 200 — 有更新** ```json { "version": 3, "models": [ { "url": "https://bailian.console.aliyun.com/...", "model_name": "qwen-plus-latest", "prices": { "256k `version` 为全局整数版本号,从 1 开始,每次爬取结果有变化时自增。 > `discount` 为调用方域名对应的折扣率,无折扣时为 `1.0`。 **Response 200 — 无需更新(version 与服务端一致)** ```json { "up_to_date": true, "version": 3 } ``` **Response 400** — 缺少 Referer header **Response 404** — 指定 url 无快照数据 **Response 503** — 快照尚未生成(未执行过爬取) --- ## 爬取任务 ### POST /api/scrape 创建爬取任务,异步执行。 **Request Body** ```json { "urls": [ "https://bailian.console.aliyun.com/...#/model-market/detail/qwen-plus", "https://bailian.console.aliyun.com/...#/model-market/detail/qwen-max" ] } ``` **Response 202** ```json { "job_id": "550e8400-e29b-41d4-a716-446655440000", "status": "pending", "error": null, "created_at": "2026-04-03T09:30:00+00:00" } ``` --- ### GET /api/scrape 获取所有爬取任务列表,按创建时间倒序。 **Response 200** ```json [ { "job_id": "550e8400-...", "status": "done", "error": null, "created_at": "2026-04-03T09:30:00+00:00" } ] ``` `status` 枚举值:`pending` | `running` | `done` | `failed` --- ### GET /api/scrape/{job_id} 获取单个任务详情,`done` 状态时包含爬取结果。 **Response 200** ```json { "job_id": "550e8400-...", "status": "done", "error": null, "created_at": "2026-04-03T09:30:00+00:00", "results": [ { "url": "...", "model_name": "qwen-plus-latest", "prices": {}, "model_info": {}, "rate_limits": {}, "tool_prices": [], "scraped_at": "2026-04-03T09:30:12+00:00" } ] } ``` **Response 404** — 任务不存在 --- ## 模型管理 ### GET /api/models 获取所有已注册模型列表。 **Response 200** ```json [ { "id": 1, "name": "qwen-plus", "url": "https://bailian.console.aliyun.com/...#/model-market/detail/qwen-plus", "created_at": "2026-04-01T00:00:00+00:00" } ] ``` --- ### POST /api/models 添加模型。 **Request Body** ```json { "name": "qwen-plus", "url": "https://bailian.console.aliyun.com/...#/model-market/detail/qwen-plus" } ``` **Response 201** — 同上结构 **Response 409** — URL 已存在 --- ### DELETE /api/models/{model_id} 删除模型。 **Response 204** — 成功 **Response 404** — 模型不存在 --- ## 定时爬取配置 ### GET /api/schedule 获取当前定时爬取配置。 **Response 200** ```json { "enabled": false, "interval_days": 1, "start_hour": 2, "updated_at": "2026-04-01T00:00:00+00:00" } ``` --- ### PUT /api/schedule 更新定时爬取配置。 **Request Body** ```json { "enabled": true, "interval_days": 1, "start_hour": 2 } ``` **Response 200** — 同上结构 --- ## 折扣管理 ### GET /api/discounts 获取所有域名折扣配置。 **Response 200** ```json [ { "id": 1, "domain": "example.com", "discount": 0.8, "note": "合作伙伴八折", "created_at": "2026-04-01T00:00:00+00:00", "updated_at": "2026-04-01T00:00:00+00:00" } ] ``` --- ### POST /api/discounts 新增或更新域名折扣(domain 唯一,重复则覆盖)。 **Request Body** ```json { "domain": "example.com", "discount": 0.8, "note": "合作伙伴八折" } ``` > `discount` 范围:`(0, 1]`,如 `0.8` 表示八折。 **Response 201** — 同上结构 --- ### PUT /api/discounts/{discount_id} 更新指定折扣记录。 **Request Body** — 同 POST **Response 200** — 同上结构 **Response 404** — 不存在 --- ### DELETE /api/discounts/{discount_id} 删除折扣记录。 **Response 204** — 成功 **Response 404** — 不存在 --- ## 系统统计 ### GET /api/stats 获取系统运行统计。 **Response 200** ```json { "uptime_seconds": 3600.5, "total_hits": 1024, "active_ips": 3, "avg_latency_ms": 45.2 } ``` > `active_ips` 为最近 5 分钟内有请求的 IP 数量。 --- ### GET /api/geo/distribution 获取访问来源国家分布。 **Response 200** ```json [ { "country": "China", "count": 800, "percentage": 78.13 } ] ``` --- ### GET /api/geo/points 获取访问来源地理坐标点(最多 1000 条)。 **Response 200** ```json [ { "latitude": 39.9042, "longitude": 116.4074, "country": "China", "city": "Beijing", "hit_count": 120 } ] ``` --- ### GET /api/prices/top-ips 获取价格接口调用量 Top 20 IP。 **Response 200** ```json [ { "ip": "127.0.0.1", "hit_count": 21, "percentage": 100.0 } ] ``` --- ## 访问日志 ### GET /api/logs 获取访问日志,支持分页。 **Query Parameters** | 参数 | 类型 | 默认值 | 说明 | |-----------|------|--------|----------------| | page | int | 1 | 页码,从 1 开始 | | page_size | int | 50 | 每页条数,最大 500 | **Response 200** ```json [ { "id": 1, "ip": "127.0.0.1", "method": "GET", "path": "/api/public/prices", "status_code": 200, "latency_ms": 45.2, "country": "China", "city": "Beijing", "latitude": 39.9042, "longitude": 116.4074, "created_at": "2026-04-03T09:30:00+00:00" } ] ``` --- ## 爬虫统计 ### GET /api/scrape-stats 获取爬虫运行统计,用于仪表盘展示。 **Response 200** ```json { "overview": { "total_jobs": 25, "success_jobs": 22, "failed_jobs": 3, "total_models_scraped": 7, "last_scraped_at": "2026-04-03T09:30:34+00:00" }, "daily_counts": [ { "date": "2026-03-05", "count": 2 }, { "date": "2026-04-03", "count": 5 } ], "model_ranks": [ { "model_name": "qwen-plus-latest", "count": 10 }, { "model_name": "qwen-max", "count": 8 } ], "recent_jobs": [ { "job_id": "550e8400-...", "status": "done", "model_count": 5, "created_at": "2026-04-03T09:30:00+00:00" } ] } ``` --- ## WebSocket ### WS /ws/logs 实时推送访问日志。连接后服务端会主动推送每条新请求的 JSON 数据,格式同 `/api/logs` 单条记录。 **连接示例** ```js const ws = new WebSocket('ws://localhost:8000/ws/logs'); ws.onmessage = (e) => console.log(JSON.parse(e.data)); ```