Files
ameiba_cn_new/docs/内容判断引擎文章发布API.md
T

262 lines
8.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 阿美巴内容判断引擎文章发布 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 转义。
## 生产验收记录
2026-09-11 已完成生产部署和以下验证:
- 有效服务端 Token 调用健康检查返回 HTTP 200;无 Token 返回 HTTP 401。
- 首次写入临时草稿返回 HTTP 201、`revision=1`。
- 相同幂等键重试返回 HTTP 200,文章 ID、URL 和 revision 保持一致。
- 新确认版本更新返回 HTTP 200,文章 ID 和 URL 保持一致,`revision` 增加到 2。
- 临时草稿始终为 `draft`,验证后已删除,未出现在“认知观察”公开列表。
- CMS 进程保持在线,官网首页返回 HTTP 200。
- 迁移前 MySQL 备份保存在服务器 `/var/backups/ameiba-cms/`。