This commit is contained in:
2026-05-08 00:05:51 +08:00
parent 549b706fcc
commit ed70a140a2
40 changed files with 5590 additions and 36 deletions
+49
View File
@@ -0,0 +1,49 @@
# API 文档总览
当前 `apidoc/` 中的文档按接口域拆分:
- [importapi.md](/www/proofdb/apidoc/importapi.md): 档案导入接口
- [adminapi.md](/www/proofdb/apidoc/adminapi.md): 管理员认证与后台维护接口
- [searchapi.md](/www/proofdb/apidoc/searchapi.md): 全文、向量、混合搜索接口
- [evidenceapi.md](/www/proofdb/apidoc/evidenceapi.md): chunk 详情与 evidence 接口
## 当前已实现接口
```http
POST /api/articles/import
POST /api/admin/login
POST /api/admin/logout
GET /api/admin/me
GET /api/admin/archives
GET /api/admin/archives/{archive_uid}
PATCH /api/admin/archives/{archive_uid}
DELETE /api/admin/archives/{archive_uid}
GET /api/admin/opensearch/status
GET /api/admin/opensearch/documents
GET /api/admin/users
POST /api/admin/users
PATCH /api/admin/users/{id}
GET /api/admin/docs
GET /api/admin/docs/{name}
GET /api/admin/scripts
GET /api/admin/scripts/{name}
POST /api/admin/scripts/run
POST /api/search/fulltext
POST /api/search/vector
POST /api/search/hybrid
GET /api/chunks/{chunk_uid}
GET /api/evidence/{chunk_uid}
```
## 当前接口分层
- 导入层:把 Markdown 档案解析为 archive / chunk,并写入 PostgreSQL。
- 管理层:管理员登录、会话识别、archives 表管理、OpenSearch 状态、用户管理、文档查看与维护脚本执行。
- 检索层:从 OpenSearch 做 BM25、向量和 hybrid 检索。
- 证据层:把 `chunk_uid` 落到 citation、页码和证据正文。
## 说明
- 搜索接口中的 `hits` 始终表示“当前请求下返回的候选结果数组”,不是数据库全量导出。
- `fulltext``vector``hybrid` 都支持 `limit`
- `hybrid``total` 表示融合后的候选总数;更细的来源统计在 `sources` 字段中。
+355
View File
@@ -0,0 +1,355 @@
# 管理员后台 API
## 接口说明
这组接口服务于 Proof DB 的管理员维护面板,包括:
- 管理员登录与会话读取
- `archives` 表管理
- OpenSearch 状态查看
- 管理员用户管理
- APIDOC 文档查看
- 维护脚本执行
管理员网页入口仍然是:
- `GET /`
- `GET /admin/login`
- `GET /admin`
## 管理员认证
### 管理员登录
```http
POST /api/admin/login
```
`Content-Type: application/json`
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `username` | string | 是 | 管理员用户名 |
| `password` | string | 是 | 管理员密码 |
### 管理员退出登录
```http
POST /api/admin/logout
```
### 当前管理员会话
```http
GET /api/admin/me
```
未登录时返回:
```json
{
"code": 401,
"message": "Admin session not found."
}
```
## archives 表管理
### 获取档案列表
```http
GET /api/admin/archives
```
### 查询参数
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `query` | string | 否 | 按 `archive_uid``title``summary``author``source``series` 模糊搜索 |
| `page` | integer | 否 | 页码,默认 `1` |
| `page_size` | integer | 否 | 每页条数,默认 `20`,最大 `100` |
### 请求示例
```bash
curl '<APIdomain>/api/admin/archives?query=iraq&page=1&page_size=20'
```
### 成功响应
```json
{
"code": 0,
"message": "Archive list loaded.",
"data": {
"items": [
{
"archive_uid": "01KQHVREB6XPYF604RVZAP9NNY",
"title": "1.test",
"summary": "....",
"year": 1991,
"author": "....",
"source": "....",
"series": null,
"tags": ["Iraq", "Kuwait"],
"chunk_count": 14,
"created_time": "2026-05-07 12:00:00+00",
"updated_time": "2026-05-07 12:10:00+00"
}
],
"total": 1,
"page": 1,
"page_size": 20
}
}
```
### 获取单条档案详情
```http
GET /api/admin/archives/{archive_uid}
```
### 更新单条档案
```http
PATCH /api/admin/archives/{archive_uid}
```
`Content-Type: application/json`
可更新字段:
- `title`
- `summary`
- `year`
- `author`
- `source`
- `series`
- `tags`
- `metadata`
- `content`
- `raw`
其中:
- `tags` 可以传字符串,也可以传数组;字符串会按逗号或换行拆分
- `metadata` 可以传 JSON 对象,也可以传 JSON 字符串
- `year` 为空时会写回 `null`
### 更新请求示例
```bash
curl -X PATCH <APIdomain>/api/admin/archives/01KQHVREB6XPYF604RVZAP9NNY \
-H 'Content-Type: application/json' \
--data '{
"title": "Updated Title",
"summary": "Updated summary",
"year": 1991,
"tags": ["Iraq", "Kuwait"],
"metadata": {
"reviewed_by": "admin"
}
}'
```
### 删除单条档案
```http
DELETE /api/admin/archives/{archive_uid}
```
删除后会因外键约束级联删除对应 `chunks` 记录。
## OpenSearch 状态查看
### 获取 OpenSearch 管理状态
```http
GET /api/admin/opensearch/status
```
### 成功响应要点
响应中会同时返回:
- OpenSearch 连接配置摘要
- PostgreSQL 侧 `archives/chunks` 数量
- `embedded_chunks`
- `indexed_chunks`
- 当前索引是否存在
- `docs_count`
- cluster 健康状态
- mapping 字段列表
如果 OpenSearch 当前不可达,仍会返回数据库部分统计,但 `opensearch.error` 会带出错误信息。
### 获取 OpenSearch 索引文档粗览
```http
GET /api/admin/opensearch/documents
```
### 查询参数
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `query` | string | 否 | 按 `title``summary``source``author``text` 等字段做粗略搜索 |
| `size` | integer | 否 | 返回条数,默认 `20`,最大 `50` |
说明:
- 这是索引粗览接口,不返回向量字段本身。
- 返回中会包含 `text_preview`,用于后台快速检查索引内容是否正确进入 OpenSearch。
## 管理员用户管理
### 获取管理员用户列表
```http
GET /api/admin/users
```
### 创建管理员用户
```http
POST /api/admin/users
```
`Content-Type: application/json`
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `username` | string | 是 | 新管理员用户名 |
| `password` | string | 是 | 新管理员密码 |
| `display_name` | string | 否 | 展示名称 |
### 更新管理员用户
```http
PATCH /api/admin/users/{id}
```
`Content-Type: application/json`
可更新字段:
- `display_name`
- `password`
- `is_active`
说明:
- `password` 为空时表示不修改
- `is_active=false` 后,该账号将不能再登录
## APIDOC 查看
### 获取文档列表
```http
GET /api/admin/docs
```
返回 `/apidoc` 目录下当前可查看的 `.md` 文档列表。
### 获取单份文档内容
```http
GET /api/admin/docs/{name}
```
例如:
```bash
curl <APIdomain>/api/admin/docs/searchapi.md
```
响应中会带:
- `name`
- `title`
- `content`
- `html`
其中:
- `content` 为原始 Markdown 文本
- `html` 为后台面板可直接渲染的 HTML
## 维护脚本伪终端
### 获取白名单脚本列表
```http
GET /api/admin/scripts
```
当前返回的是允许在管理员面板里执行的 `scripts/*.php` 白名单,而不是任意文件系统扫描。
如果对应脚本在 `/scriptdoc` 中存在同名文档,列表接口也会带出:
- `doc_title`
- `doc_html`
- `doc_content`
### 获取单个维护脚本详情
```http
GET /api/admin/scripts/{name}
```
这个接口会返回单个脚本的说明、参数提示,以及可用的脚本文档内容。
### 执行维护脚本
```http
POST /api/admin/scripts/run
```
`Content-Type: application/json`
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `script_name` | string | 是 | 白名单脚本名,如 `reindex_opensearch` |
| `args` | string[] | 否 | 参数数组,仅允许 `--key=value` 风格 |
### 请求示例
```bash
curl -X POST <APIdomain>/api/admin/scripts/run \
-H 'Content-Type: application/json' \
--data '{
"script_name": "reindex_opensearch",
"args": ["--archive_uid=01KQHVREB6XPYF604RVZAP9NNY"]
}'
```
### 成功响应
```json
{
"code": 0,
"message": "Maintenance script finished.",
"data": {
"script_name": "reindex_opensearch",
"command": [
"php",
"scripts/reindex_opensearch.php",
"--archive_uid=01KQHVREB6XPYF604RVZAP9NNY"
],
"exit_code": 0,
"stdout": "....",
"stderr": "",
"ok": true
}
}
```
## 权限与错误语义
-`POST /api/admin/login` 外,本文件中的所有接口都要求已有管理员会话。
- 未登录时统一返回 `401`
- 参数不合法时通常返回 `422`
- JSON 格式错误时返回 `400`
- 后端异常时返回 `500`
+382
View File
@@ -0,0 +1,382 @@
# Chunk 与 Evidence API
## 接口说明
这组接口用于把搜索结果落到可读的证据对象。
- `GET /api/archives/{archive_uid}` 返回 archive 级详情。
- `GET /api/archives/{archive_uid}/chunks` 返回该 archive 下的 chunk 列表。
- `GET /api/archives/{archive_uid}/evidence` 返回该 archive 下适合引用/AI 消费的证据列表。
- `GET /api/chunks/{chunk_uid}` 偏底层,返回 chunk 详情和所属 archive 信息。
- `GET /api/evidence/{chunk_uid}` 偏引用与展示,返回 citation、页码标签和证据正文。
其中 archive 接口以 `archive_uid` 为主键,另外两者以 `chunk_uid` 为主键。
## Archive 详情
```http
GET /api/archives/{archive_uid}
```
### 请求示例
```bash
curl <APIdomain>/api/archives/01KQHVREB6XPYF604RVZAP9NNY
```
### 成功响应
状态码:
```http
200 OK
```
响应示例:
```json
{
"code": 0,
"message": "Archive loaded.",
"data": {
"archive_uid": "01KQHVREB6XPYF604RVZAP9NNY",
"title": "1.test",
"summary": "This directive, signed by Brent Scowcroft ...",
"year": 1992,
"author": "Brent Scowcroft",
"source": "test/1.test.md",
"series": null,
"tags": ["National Security", "Policy"],
"metadata": {
"ai_enrichment": {
"provider": "bigmodel"
}
},
"content": "full normalized archive content ...",
"raw": "# 1.test ...",
"chunks": [
"01KQHVREB6XPYF604RVZAP9NNY_1_39003",
"01KQHVREB6XPYF604RVZAP9NNY_2_12345"
],
"chunk_count": 14
}
}
```
说明:
- `content` 是归一化后的 archive 正文。
- `raw` 是导入时保存的原始 Markdown。
- `chunks` 是当前 archive 关联的 `chunk_uid` 列表。
- `chunk_count` 方便调用方快速判断档案规模,而不必自己数数组长度。
### 错误响应
#### archive 不存在
状态码:
```http
404 Not Found
```
```json
{
"code": 404,
"message": "Archive not found.",
"errors": {
"archive_uid": "missing_archive_uid"
}
}
```
## Archive 下的 Chunk 列表
```http
GET /api/archives/{archive_uid}/chunks
```
### 请求示例
```bash
curl <APIdomain>/api/archives/01KQHVREB6XPYF604RVZAP9NNY/chunks
```
### 成功响应
状态码:
```http
200 OK
```
响应示例:
```json
{
"code": 0,
"message": "Archive chunks loaded.",
"data": {
"archive_uid": "01KQHVREB6XPYF604RVZAP9NNY",
"title": "1.test",
"summary": "This directive, signed by Brent Scowcroft ...",
"source": "test/1.test.md",
"author": "Brent Scowcroft",
"year": 1992,
"series": null,
"tags": ["National Security", "Policy"],
"chunk_count": 14,
"chunks": [
{
"chunk_uid": "01KQHVREB6XPYF604RVZAP9NNY_1_39003",
"archive_uid": "01KQHVREB6XPYF604RVZAP9NNY",
"chunk_index": 1,
"page_start": 1,
"page_end": 1,
"pages": [1],
"text": "chunk text...",
"length": 300,
"embedding_status": 3,
"embedding_ref": {
"provider": "bigmodel",
"model": "embedding-3",
"dimensions": 2048
},
"embedding_model": "embedding-3",
"embedding_error": null,
"search_index_status": 3,
"search_index_error": null,
"archive": {
"archive_uid": "01KQHVREB6XPYF604RVZAP9NNY",
"title": "1.test",
"summary": "This directive, signed by Brent Scowcroft ...",
"year": 1992,
"author": "Brent Scowcroft",
"source": "test/1.test.md",
"series": null,
"tags": ["National Security", "Policy"],
"metadata": {}
}
}
]
}
}
```
说明:
- 这个接口偏底层,适合按 archive 批量读取完整 chunk 数据。
- `chunks``chunk_index` 升序返回。
## Archive 级 Evidence 列表
```http
GET /api/archives/{archive_uid}/evidence
```
### 请求示例
```bash
curl <APIdomain>/api/archives/01KQHVREB6XPYF604RVZAP9NNY/evidence
```
### 成功响应
状态码:
```http
200 OK
```
响应示例:
```json
{
"code": 0,
"message": "Archive evidence loaded.",
"data": {
"archive_uid": "01KQHVREB6XPYF604RVZAP9NNY",
"title": "1.test",
"summary": "This directive, signed by Brent Scowcroft ...",
"source": "test/1.test.md",
"author": "Brent Scowcroft",
"year": 1992,
"series": null,
"tags": ["National Security", "Policy"],
"chunk_count": 14,
"evidence": [
{
"chunk_uid": "01KQHVREB6XPYF604RVZAP9NNY_1_39003",
"chunk_index": 1,
"page_start": 1,
"page_end": 1,
"pages": [1],
"page_label": "p. 1",
"citation": "1.test | Brent Scowcroft | 1992 | p. 1 | test/1.test.md",
"quote": "chunk text...",
"length": 300,
"embedding_model": "embedding-3",
"embedding_status": 3,
"search_index_status": 3
}
]
}
}
```
说明:
- 这个接口偏上层,适合 AI、RAG、引用构造和前端证据列表展示。
- `evidence` 里的每一项都保留了 citation 所需的页码和引用文本。
## Chunk 详情
```http
GET /api/chunks/{chunk_uid}
```
### 请求示例
```bash
curl <APIdomain>/api/chunks/01KQHVREB6XPYF604RVZAP9NNY_14_97554
```
### 成功响应
状态码:
```http
200 OK
```
响应示例:
```json
{
"code": 0,
"message": "Chunk loaded.",
"data": {
"chunk_uid": "01KQHVREB6XPYF604RVZAP9NNY_14_97554",
"archive_uid": "01KQHVREB6XPYF604RVZAP9NNY",
"chunk_index": 14,
"page_start": 8,
"page_end": 8,
"pages": [8],
"text": "NSD 45 20 AUG 90 U.S. Policy in Response to the Iraqi Invasion of Kuwait ...",
"length": 148,
"embedding_status": 3,
"embedding_ref": {
"provider": "bigmodel",
"model": "embedding-3",
"dimensions": 2048
},
"embedding_model": "embedding-3",
"embedding_error": null,
"search_index_status": 3,
"search_index_error": null,
"archive": {
"archive_uid": "01KQHVREB6XPYF604RVZAP9NNY",
"title": "1.test",
"summary": null,
"year": 1992,
"author": "Brent Scowcroft",
"source": "test/1.test.md",
"series": null,
"tags": [],
"metadata": {}
}
}
}
```
### 错误响应
#### chunk 不存在
状态码:
```http
404 Not Found
```
```json
{
"code": 404,
"message": "Chunk not found.",
"errors": {
"chunk_uid": "missing_chunk_uid"
}
}
```
## Evidence 详情
```http
GET /api/evidence/{chunk_uid}
```
### 请求示例
```bash
curl <APIdomain>/api/evidence/01KQHVREB6XPYF604RVZAP9NNY_14_97554
```
### 成功响应
状态码:
```http
200 OK
```
响应示例:
```json
{
"code": 0,
"message": "Evidence loaded.",
"data": {
"chunk_uid": "01KQHVREB6XPYF604RVZAP9NNY_14_97554",
"archive_uid": "01KQHVREB6XPYF604RVZAP9NNY",
"title": "1.test",
"source": "test/1.test.md",
"author": "Brent Scowcroft",
"year": 1992,
"series": null,
"tags": [],
"page_start": 8,
"page_end": 8,
"pages": [8],
"page_label": "p. 8",
"citation": "1.test | Brent Scowcroft | 1992 | p. 8 | test/1.test.md",
"quote": "NSD 45 20 AUG 90 U.S. Policy in Response to the Iraqi Invasion of Kuwait ...",
"chunk": {
"chunk_index": 14,
"length": 148,
"embedding_model": "embedding-3",
"embedding_status": 3,
"search_index_status": 3
}
}
}
```
### 错误响应
#### evidence 不存在
状态码:
```http
404 Not Found
```
```json
{
"code": 404,
"message": "Evidence not found.",
"errors": {
"chunk_uid": "missing_chunk_uid"
}
}
```
+3 -3
View File
@@ -90,7 +90,7 @@ POST /api/articles/import
## 请求示例
```bash
curl -X POST http://127.0.0.1:8787/api/articles/import \
curl -X POST <APIdomain>/api/articles/import \
-F 'title=NSD 76 Disposition of NSC Policy Documents' \
-F 'source=archive://nsc/nsd-76' \
-F 'chunk_size=800' \
@@ -101,7 +101,7 @@ curl -X POST http://127.0.0.1:8787/api/articles/import \
也可以直接发送 Markdown 原文:
```bash
curl -X POST 'http://127.0.0.1:8787/api/articles/import?title=NSD%2076&source=archive://nsc/nsd-76' \
curl -X POST '<APIdomain>/api/articles/import?title=NSD%2076&source=archive://nsc/nsd-76' \
-H 'Content-Type: text/markdown' \
--data-binary '@test/1.test.md'
```
@@ -109,7 +109,7 @@ curl -X POST 'http://127.0.0.1:8787/api/articles/import?title=NSD%2076&source=ar
JSON 调用示例:
```bash
curl -X POST http://127.0.0.1:8787/api/articles/import \
curl -X POST <APIdomain>/api/articles/import \
-H 'Content-Type: application/json' \
--data '{
"title": "NSD 76 Disposition of NSC Policy Documents",
+33 -16
View File
@@ -7,6 +7,7 @@ Proof DB 的搜索接口基于 OpenSearch `proofdb_chunks` 索引。当前版本
OpenSearch 中每个 chunk 文档同时包含:
- `text` 等全文字段,用于 BM25 检索。
- `summary` 档案摘要字段,会参与全文检索,也会随搜索结果一起返回。
- `embedding` 2048 维向量字段,用于后续 vector / hybrid 检索。
## 全文搜索
@@ -35,7 +36,7 @@ POST /api/search/fulltext
### 请求示例
```bash
curl -X POST http://127.0.0.1:8787/api/search/fulltext \
curl -X POST <APIdomain>/api/search/fulltext \
-H 'Content-Type: application/json' \
--data '{
"query": "policy documents",
@@ -46,7 +47,7 @@ curl -X POST http://127.0.0.1:8787/api/search/fulltext \
带过滤条件:
```bash
curl -X POST http://127.0.0.1:8787/api/search/fulltext \
curl -X POST <APIdomain>/api/search/fulltext \
-H 'Content-Type: application/json' \
--data '{
"query": "Iraq Kuwait",
@@ -87,6 +88,7 @@ curl -X POST http://127.0.0.1:8787/api/search/fulltext \
"page_start": 1,
"page_end": 1,
"title": "NSD 76 Disposition of NSC Policy Documents",
"summary": "Summary text...",
"source": "archive://nsc/nsd-76",
"author": "Brent Scowcroft",
"year": 1992,
@@ -101,6 +103,12 @@ curl -X POST http://127.0.0.1:8787/api/search/fulltext \
}
```
说明:
- `hits` 是当前返回的结果数组。
- `total` 是当前 full-text 查询下的命中总数。
- 全文搜索当前会综合匹配 `text``title``summary``source``author``series``tags`
### 错误响应
#### JSON 格式错误
@@ -157,8 +165,6 @@ curl -X POST http://127.0.0.1:8787/api/search/fulltext \
}
```
## 后续接口
## 向量搜索
```http
@@ -179,7 +185,7 @@ POST /api/search/vector
### 请求示例
```bash
curl -X POST http://127.0.0.1:8787/api/search/vector \
curl -X POST <APIdomain>/api/search/vector \
-H 'Content-Type: application/json' \
--data '{
"query": "Iraq invasion and Desert Storm",
@@ -191,7 +197,7 @@ curl -X POST http://127.0.0.1:8787/api/search/vector \
中文 query 也可以提交给向量搜索:
```bash
curl -X POST http://127.0.0.1:8787/api/search/vector \
curl -X POST <APIdomain>/api/search/vector \
-H 'Content-Type: application/json' \
--data '{
"query": "伊拉克入侵科威特与沙漠风暴",
@@ -231,6 +237,7 @@ curl -X POST http://127.0.0.1:8787/api/search/vector \
"page_start": 8,
"page_end": 8,
"title": "NSD 76 Disposition of NSC Policy Documents",
"summary": "Summary text...",
"source": "archive://nsc/nsd-76",
"author": "Brent Scowcroft",
"year": 1992,
@@ -246,6 +253,12 @@ curl -X POST http://127.0.0.1:8787/api/search/vector \
```
说明:
- `hits` 是当前返回的结果数组。
- `total` 是当前 vector 查询返回的候选总数。
- `embedding_dimensions` 是本次 query embedding 的维度,而不是索引总维度统计字段。
### 错误响应
错误响应格式与全文搜索一致。常见错误包括:
@@ -254,8 +267,6 @@ curl -X POST http://127.0.0.1:8787/api/search/vector \
- 缺少 `query``422 Unprocessable Entity`
- embedding API 或 OpenSearch 查询失败:`500 Internal Server Error`
## 后续接口
## 混合搜索
```http
@@ -290,7 +301,7 @@ POST /api/search/hybrid
### 请求示例
```bash
curl -X POST http://127.0.0.1:8787/api/search/hybrid \
curl -X POST <APIdomain>/api/search/hybrid \
-H 'Content-Type: application/json' \
--data '{
"query": "Iraq invasion and Desert Storm",
@@ -302,7 +313,7 @@ curl -X POST http://127.0.0.1:8787/api/search/hybrid \
中文 query
```bash
curl -X POST http://127.0.0.1:8787/api/search/hybrid \
curl -X POST <APIdomain>/api/search/hybrid \
-H 'Content-Type: application/json' \
--data '{
"query": "伊拉克入侵科威特与沙漠风暴",
@@ -370,6 +381,7 @@ curl -X POST http://127.0.0.1:8787/api/search/hybrid \
"archive_uid": "01KQHVREB6XPYF604RVZAP9NNY",
"page_start": 8,
"page_end": 8,
"summary": "Summary text...",
"text": "chunk text..."
}
]
@@ -377,6 +389,14 @@ curl -X POST http://127.0.0.1:8787/api/search/hybrid \
}
```
说明:
- `hits` 是融合排序后的结果数组。
- `total` 是融合后的候选总数。
- `sources.fulltext_total``sources.vector_total` 分别表示两路召回的原始统计。
- `rank_sources` 用于说明某条结果在 fulltext / vector 两路中的排名与 RRF 贡献。
- `summary` 来自 archive 级摘要元数据,不是 chunk 单独生成的摘要。
### 错误响应
错误响应格式与全文搜索一致。常见错误包括:
@@ -385,11 +405,8 @@ curl -X POST http://127.0.0.1:8787/api/search/hybrid \
- 缺少 `query``422 Unprocessable Entity`
- embedding API、全文搜索或向量搜索失败:`500 Internal Server Error`
## 后续接口
## 相关接口
以下能力尚未实现
与搜索结果配套的证据查看接口见
```http
GET /api/chunks/{chunk_uid}
GET /api/evidence/{chunk_uid}
```
- [evidenceapi.md](/www/proofdb/apidoc/evidenceapi.md)