250 lines
8.0 KiB
Markdown
250 lines
8.0 KiB
Markdown
# 阿美巴内容判断引擎文章发布 API
|
||
|
||
版本:V1
|
||
站点身份:`human`
|
||
公开栏目:认知观察
|
||
生产站点:`https://www.ameiba.cn`
|
||
|
||
本文档供“阿美巴内容判断引擎”调用传统官网发布接口。网站只接收人工确认终稿、保存并安全排版,不调用 AI 二次修改正文。
|
||
|
||
## 接口配置
|
||
|
||
```text
|
||
base_url=https://www.ameiba.cn
|
||
health_path=/api/internal/content/v1/health
|
||
upsert_path=/api/internal/content/v1/articles/upsert
|
||
auth_type=Bearer
|
||
token_environment_name=CONTENT_INGEST_TOKEN
|
||
site_profile=human
|
||
public_url_rule=https://www.ameiba.cn/insights/{slug}
|
||
```
|
||
|
||
所有请求必须使用 HTTPS,并在请求头携带:
|
||
|
||
```http
|
||
Authorization: Bearer <CONTENT_INGEST_TOKEN>
|
||
```
|
||
|
||
发布密钥只保存在双方服务端环境变量中,不得写入前端、Git、请求日志或普通业务日志。
|
||
|
||
## 1. 健康检查
|
||
|
||
```http
|
||
GET /api/internal/content/v1/health
|
||
Authorization: Bearer <CONTENT_INGEST_TOKEN>
|
||
```
|
||
|
||
成功响应,HTTP 200:
|
||
|
||
```json
|
||
{
|
||
"status": "ok",
|
||
"service": "amaba-human-website",
|
||
"site_profile": "human",
|
||
"api_version": "v1"
|
||
}
|
||
```
|
||
|
||
## 2. 新增或更新文章
|
||
|
||
```http
|
||
POST /api/internal/content/v1/articles/upsert
|
||
Authorization: Bearer <CONTENT_INGEST_TOKEN>
|
||
Content-Type: application/json
|
||
Idempotency-Key: <source_task_id>:<source_version_id>:human
|
||
```
|
||
|
||
请求示例:
|
||
|
||
```json
|
||
{
|
||
"request_id": "01JEXAMPLE",
|
||
"source_system": "amaba-content-core",
|
||
"source_task_id": "69900421-8edd-4fb3-9bc6-f656348a416c",
|
||
"source_version_id": "af6a2665-f8f3-4f16-b99e-14372a311bf8",
|
||
"source_version_number": 2,
|
||
"content_hash": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
|
||
"site_profile": "human",
|
||
"publish_mode": "publish",
|
||
"article": {
|
||
"title": "文章标题",
|
||
"body_plain": "第一自然段。\n第二自然段。",
|
||
"summary": "列表页摘要",
|
||
"slug": "example-slug",
|
||
"primary_keyword": "企业AI进化",
|
||
"keywords": ["企业AI", "组织进化"],
|
||
"content_type": "industry",
|
||
"direction": "行业观察",
|
||
"target_audience": "企业经营者与管理者",
|
||
"author_name": "阿美巴",
|
||
"cover_image_url": null,
|
||
"canonical_url": null
|
||
},
|
||
"quality": {
|
||
"human_confirmed": true,
|
||
"confirmed_at": "2026-09-11T10:00:00+08:00",
|
||
"prompt_version": "AmAba-Audit-V1.2",
|
||
"judgment_version": "AmAba-Judgment-V1.1",
|
||
"model": "deepseek",
|
||
"remaining_issue_levels": ["P3"]
|
||
},
|
||
"provenance": {
|
||
"knowledge_refs": [
|
||
{"id": "knowledge-id", "name": "知识名称", "version": "1.0"}
|
||
]
|
||
},
|
||
"semantic": {
|
||
"entities": ["阿美巴", "企业AI进化"],
|
||
"questions": [],
|
||
"facts": [],
|
||
"suggested_schema_type": "Article"
|
||
}
|
||
}
|
||
```
|
||
|
||
首次创建成功返回 HTTP 201:
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"publication_id": "art-网站文章ID",
|
||
"status": "published",
|
||
"url": "https://www.ameiba.cn/insights/example-slug",
|
||
"revision": 1,
|
||
"content_hash": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
|
||
"published_at": "2026-09-11T10:01:20.000Z"
|
||
}
|
||
```
|
||
|
||
同一来源任务的新确认版本会更新原文章,保留原 `publication_id` 和原公开 URL,`revision` 加 1,返回 HTTP 200。相同幂等键的安全重试也返回 HTTP 200。
|
||
|
||
## 字段和校验规则
|
||
|
||
- `source_system` 固定为 `amaba-content-core`。
|
||
- `site_profile` 固定为 `human`。
|
||
- `quality.human_confirmed` 必须严格为 `true`。
|
||
- `source_version_number` 必须是正整数;更新时必须高于网站当前版本,防止旧版本倒序覆盖。
|
||
- `content_hash` 必须为 64 位 SHA-256 十六进制字符串。
|
||
- `publish_mode` 支持 `publish` 和 `draft`。
|
||
- `article.title` 最长 200 字符。
|
||
- `article.body_plain` 最长 200,000 字符。
|
||
- `article.summary` 最长 1,000 字符。
|
||
- 关键词、问题、实体、事实、知识引用等数组最多 30 项。
|
||
- `slug` 可省略;提供时仅允许小写字母、数字和连字符。
|
||
- `cover_image_url` 和 `canonical_url` 仅接受 HTTP/HTTPS URL。
|
||
- 接口默认按来源 IP 每分钟限制 30 次,可用 `CONTENT_INGEST_RATE_LIMIT` 调整。
|
||
|
||
## 正文安全处理
|
||
|
||
`body_plain` 被视为不可信纯文本。服务端会:
|
||
|
||
1. 统一换行符。
|
||
2. 按单换行拆分自然段并忽略空行。
|
||
3. 转义 `& < > " '` 等 HTML 特殊字符。
|
||
4. 每个自然段生成独立 `<p>` 存入 `content_html`。
|
||
5. 同时原样保存规范化后的 `body_plain`。
|
||
|
||
前端使用 React 文本节点按自然段渲染,不使用 `dangerouslySetInnerHTML`,因此正文中的 HTML 或 JavaScript 不会执行。
|
||
|
||
## 幂等和文章唯一性
|
||
|
||
标准幂等键:
|
||
|
||
```text
|
||
<source_task_id>:<source_version_id>:human
|
||
```
|
||
|
||
规则:
|
||
|
||
- `UNIQUE(idempotency_key)` 防止同一版本重复发布。
|
||
- `UNIQUE(source_system, source_task_id, site_profile)` 保证同一内容任务始终对应同一网站文章和公开 URL。
|
||
- 每个发布过的幂等键同时写入 `article_ingest_requests`,因此旧版本请求在新版本发布后重试仍可正确识别。
|
||
- 相同幂等键和相同哈希:返回原 `publication_id` 与 URL,不写入重复文章。
|
||
- 相同幂等键但哈希不同:返回 HTTP 409,不静默覆盖。
|
||
- 新 `source_version_id` 和新幂等键:更新原文章,保留 slug,`revision + 1`。
|
||
|
||
## 数据库增量迁移
|
||
|
||
现有 MySQL `articles` 表增量增加:
|
||
|
||
```text
|
||
source_system, source_task_id, source_version_id, source_version_number,
|
||
site_profile, idempotency_key, content_hash, body_plain, revision,
|
||
primary_keyword, keywords_json, content_type, direction, target_audience,
|
||
author_name, human_confirmed, confirmed_at, request_id, canonical_url,
|
||
quality_json, provenance_json, semantic_json
|
||
```
|
||
|
||
新增关联表 `article_ingest_requests` 保存历史幂等键、文章 ID、版本 ID、哈希和当次 revision。迁移位于 `cms/server/src/db.js` 的现有启动迁移流程中,CMS 正常启动时通过 `SHOW COLUMNS`、`ALTER TABLE ADD COLUMN` 和 `CREATE TABLE IF NOT EXISTS` 执行;不会删除、清空或重建现有文章表。
|
||
|
||
## 错误响应
|
||
|
||
统一格式:
|
||
|
||
```json
|
||
{
|
||
"success": false,
|
||
"error": {
|
||
"code": "VALIDATION_ERROR",
|
||
"message": "article.title不能为空",
|
||
"retryable": false
|
||
}
|
||
}
|
||
```
|
||
|
||
| HTTP | code | 是否建议自动重试 | 说明 |
|
||
| --- | --- | --- | --- |
|
||
| 400 | `VALIDATION_ERROR` | 否 | 请求字段或幂等键格式错误 |
|
||
| 401 | `UNAUTHORIZED` | 否 | 缺少或错误 Token |
|
||
| 403 | `HUMAN_CONFIRMATION_REQUIRED` | 否 | 不是人工确认终稿 |
|
||
| 403 | `SOURCE_NOT_ALLOWED` / `SITE_PROFILE_MISMATCH` | 否 | 来源系统或站点身份错误 |
|
||
| 409 | `CONTENT_CONFLICT` | 否,需人工检查 | 幂等哈希、slug 或版本冲突 |
|
||
| 413 | `CONTENT_TOO_LARGE` | 否 | 正文或元数据超过限制 |
|
||
| 429 | `RATE_LIMITED` | 是 | 请求频率超过限制 |
|
||
| 500 | `INTERNAL_ERROR` | 是 | 网站内部错误 |
|
||
| 503 | `SERVICE_UNAVAILABLE` | 是 | 生产环境未配置发布密钥或服务暂不可用 |
|
||
|
||
## curl 示例
|
||
|
||
健康检查:
|
||
|
||
```bash
|
||
curl -H "Authorization: Bearer $CONTENT_INGEST_TOKEN" \
|
||
https://www.ameiba.cn/api/internal/content/v1/health
|
||
```
|
||
|
||
发布文章:
|
||
|
||
```bash
|
||
curl -X POST \
|
||
-H "Authorization: Bearer $CONTENT_INGEST_TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-H "Idempotency-Key: 69900421-8edd-4fb3-9bc6-f656348a416c:af6a2665-f8f3-4f16-b99e-14372a311bf8:human" \
|
||
--data @article-publish.json \
|
||
https://www.ameiba.cn/api/internal/content/v1/articles/upsert
|
||
```
|
||
|
||
## 环境变量
|
||
|
||
```dotenv
|
||
CONTENT_INGEST_TOKEN=双方服务端共享的高强度随机密钥
|
||
CONTENT_INGEST_RATE_LIMIT=30
|
||
PUBLIC_SITE_URL=https://www.ameiba.cn
|
||
```
|
||
|
||
仓库中的 `cms/server/.env.example` 只提供空值名称。真实值写入服务器的 `/var/www/ameiba-cn-new/cms/server/.env`,不得提交 Git。
|
||
|
||
## 本地验证
|
||
|
||
```bash
|
||
cd cms/server
|
||
npm install
|
||
npm test
|
||
|
||
cd ../..
|
||
npm install
|
||
npm run build
|
||
```
|
||
|
||
当前验收结果:内部发布接口自动化测试 12 项通过;前端 TypeScript 与 Vite 生产构建通过。自动化测试覆盖 Token、健康检查、字段校验、人工确认、站点身份、首次创建、幂等重试、哈希冲突、同 URL 更新、revision 增长、自然段转换与 XSS 转义。
|