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

8.0 KiB
Raw Blame History

阿美巴内容判断引擎文章发布 API

版本:V1
站点身份:human
公开栏目:认知观察
生产站点:https://www.ameiba.cn

本文档供“阿美巴内容判断引擎”调用传统官网发布接口。网站只接收人工确认终稿、保存并安全排版,不调用 AI 二次修改正文。

接口配置

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,并在请求头携带:

Authorization: Bearer <CONTENT_INGEST_TOKEN>

发布密钥只保存在双方服务端环境变量中,不得写入前端、Git、请求日志或普通业务日志。

1. 健康检查

GET /api/internal/content/v1/health
Authorization: Bearer <CONTENT_INGEST_TOKEN>

成功响应,HTTP 200:

{
  "status": "ok",
  "service": "amaba-human-website",
  "site_profile": "human",
  "api_version": "v1"
}

2. 新增或更新文章

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

请求示例:

{
  "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:

{
  "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 不会执行。

幂等和文章唯一性

标准幂等键:

<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 表增量增加:

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 执行;不会删除、清空或重建现有文章表。

错误响应

统一格式:

{
  "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 示例

健康检查:

curl -H "Authorization: Bearer $CONTENT_INGEST_TOKEN" \
  https://www.ameiba.cn/api/internal/content/v1/health

发布文章:

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

环境变量

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。

本地验证

cd cms/server
npm install
npm test

cd ../..
npm install
npm run build

当前验收结果:内部发布接口自动化测试 12 项通过;前端 TypeScript 与 Vite 生产构建通过。自动化测试覆盖 Token、健康检查、字段校验、人工确认、站点身份、首次创建、幂等重试、哈希冲突、同 URL 更新、revision 增长、自然段转换与 XSS 转义。