- 产品编辑入口统一走 ProductFormFull(卖点/风格/人群/品牌词全字段); 修复开任务页 <form> 套 <form> 致"编辑产品"报错、改不了、跳回首个产品 - dashboard 入口卡片对齐实际路由: 系统管理(/config) 与 工作配置(/settings) 分开; settings ?tab=products 直达改用挂载后读 URL, 消除 hydration mismatch - 新增用户管理(users API/admin service/改密页) + alembic 022/023/024 - 上线部署: Dockerfile / docker-compose.prod+https / nginx https / .env.example - A8 三套正交叙事(痛点/场景/成分背书) + beige 调色去AI化 + 飞轮 text_import 高权重信号 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
883 lines
25 KiB
YAML
883 lines
25 KiB
YAML
openapi: "3.0.3"
|
||
info:
|
||
title: Clover API
|
||
version: "1.0.0"
|
||
description: "小红书内容生产平台 Clover — 一期 1A+1B"
|
||
|
||
servers:
|
||
- url: /api/v1
|
||
|
||
security:
|
||
- BearerAuth: []
|
||
|
||
components:
|
||
securitySchemes:
|
||
BearerAuth:
|
||
type: http
|
||
scheme: bearer
|
||
bearerFormat: JWT
|
||
|
||
schemas:
|
||
# ── 通用包络 ──
|
||
SuccessEnvelope:
|
||
type: object
|
||
properties:
|
||
code: { type: integer, example: 0 }
|
||
data: { type: object }
|
||
|
||
ErrorEnvelope:
|
||
type: object
|
||
properties:
|
||
code: { type: integer, example: 40001 }
|
||
message: { type: string }
|
||
|
||
Pagination:
|
||
type: object
|
||
properties:
|
||
items: { type: array, items: { type: object } }
|
||
total: { type: integer }
|
||
page: { type: integer }
|
||
page_size: { type: integer }
|
||
|
||
# ── 认证 ──
|
||
LoginRequest:
|
||
type: object
|
||
required: [username, password]
|
||
properties:
|
||
username: { type: string }
|
||
password: { type: string }
|
||
|
||
LoginData:
|
||
type: object
|
||
properties:
|
||
token: { type: string }
|
||
user:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
username: { type: string }
|
||
email: { type: string }
|
||
current_workspace_id: { type: integer }
|
||
role: { type: string, enum: [admin, supervisor, operator] }
|
||
must_change_password: { type: boolean }
|
||
|
||
ChangePasswordRequest:
|
||
type: object
|
||
required: [current_password, new_password]
|
||
properties:
|
||
current_password: { type: string }
|
||
new_password: { type: string, minLength: 10 }
|
||
|
||
MeData:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
username: { type: string }
|
||
email: { type: string }
|
||
current_workspace_id: { type: integer }
|
||
role: { type: string }
|
||
must_change_password: { type: boolean }
|
||
workspace:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
name: { type: string }
|
||
slug: { type: string }
|
||
|
||
SwitchWorkspaceRequest:
|
||
type: object
|
||
required: [workspace_id]
|
||
properties:
|
||
workspace_id: { type: integer }
|
||
|
||
SwitchWorkspaceData:
|
||
type: object
|
||
properties:
|
||
current_workspace_id: { type: integer }
|
||
role: { type: string }
|
||
token: { type: string }
|
||
|
||
# ── API Key ──
|
||
ApiKeyItem:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
provider: { type: string, example: openai }
|
||
key_last4: { type: string, example: ab12 }
|
||
created_at: { type: string, format: date-time }
|
||
|
||
ApiKeyCreateRequest:
|
||
type: object
|
||
required: [provider, api_key]
|
||
properties:
|
||
provider: { type: string }
|
||
api_key: { type: string, description: "明文key仅传输,后端Fernet加密存储" }
|
||
|
||
# ── 产品档案 ──
|
||
ProductCreateRequest:
|
||
type: object
|
||
required: [name, category, source]
|
||
properties:
|
||
name: { type: string }
|
||
category: { type: string, description: "纯数据字段,不枚举" }
|
||
source: { type: string, enum: [preset, custom] }
|
||
selling_points: { type: array, items: { type: string } }
|
||
style_tone: { type: string }
|
||
text_angles: { type: array, items: { type: string } }
|
||
custom_prompt: { type: string, nullable: true }
|
||
banned_word_ids: { type: array, items: { type: integer } }
|
||
|
||
ProductItem:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
name: { type: string }
|
||
category: { type: string }
|
||
source: { type: string }
|
||
selling_points: { type: array, items: { type: string } }
|
||
style_tone: { type: string }
|
||
text_angles: { type: array, items: { type: string } }
|
||
custom_prompt: { type: string, nullable: true }
|
||
workspace_id: { type: integer }
|
||
created_at: { type: string, format: date-time }
|
||
|
||
# ── 标杆笔记 ──
|
||
BenchmarkCreateRequest:
|
||
type: object
|
||
properties:
|
||
screenshot_url:
|
||
type: string
|
||
nullable: true
|
||
description: 兼容旧字段;新前端不再把外部链接存到这里
|
||
highlights: { type: string }
|
||
link_url: { type: string, nullable: true }
|
||
|
||
BenchmarkItem:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
product_id: { type: integer }
|
||
screenshot_url: { type: string, nullable: true }
|
||
highlights: { type: string }
|
||
link_url: { type: string, nullable: true }
|
||
features:
|
||
type: object
|
||
nullable: true
|
||
additionalProperties: true
|
||
analyze_status: { type: string, enum: [pending, analyzing, done, failed] }
|
||
analysis_source: { type: string, nullable: true }
|
||
analysis_warning: { type: string, nullable: true }
|
||
created_at: { type: string, format: date-time }
|
||
|
||
# ── 违禁词 ──
|
||
BannedWordItem:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
word: { type: string }
|
||
level: { type: string, enum: [auto_fix, soft_warn, hard_block] }
|
||
replacement: { type: string, nullable: true }
|
||
updatable: { type: boolean }
|
||
workspace_id: { type: integer }
|
||
|
||
BannedWordRequest:
|
||
type: object
|
||
required: [word, level]
|
||
properties:
|
||
word: { type: string }
|
||
level: { type: string, enum: [auto_fix, soft_warn, hard_block] }
|
||
replacement: { type: string, nullable: true }
|
||
updatable: { type: boolean, default: true }
|
||
|
||
# ── 生产任务 ──
|
||
TaskCreateRequest:
|
||
type: object
|
||
required: [product_id, theme, text_count, image_count, track]
|
||
properties:
|
||
product_id: { type: integer }
|
||
benchmark_ids: { type: array, items: { type: integer } }
|
||
theme: { type: string, description: "今天主题,如'夏日清爽控油'" }
|
||
text_count: { type: integer, description: "用户设定,不写死" }
|
||
image_count: { type: integer, description: "用户设定,不写死" }
|
||
track: { type: string, enum: [ai, import], description: "ai=轨A生成/import=轨B导入" }
|
||
|
||
TaskListItem:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
product_id: { type: integer }
|
||
theme: { type: string }
|
||
status:
|
||
type: string
|
||
enum: [pending, generating, pending_selection, pending_review, approved, rejected, archived, failed]
|
||
created_at: { type: string, format: date-time }
|
||
text_count: { type: integer }
|
||
image_count: { type: integer }
|
||
track: { type: string, enum: [ai, import] }
|
||
need_product_image: { type: boolean }
|
||
review_status: { type: string, nullable: true }
|
||
reject_reason: { type: string, nullable: true }
|
||
reviewed_at: { type: string, format: date-time, nullable: true }
|
||
|
||
TextCandidateScore:
|
||
type: object
|
||
properties:
|
||
title: { type: integer, maximum: 25 }
|
||
emotion: { type: integer, maximum: 25 }
|
||
selling: { type: integer, maximum: 25 }
|
||
keyword: { type: integer, maximum: 20 }
|
||
compliance: { type: integer, maximum: 5 }
|
||
total: { type: integer, maximum: 100 }
|
||
|
||
TextCandidateItem:
|
||
type: object
|
||
properties:
|
||
candidate_id: { type: integer }
|
||
angle_label: { type: string }
|
||
strategy: { type: string, enum: [A, B, C], nullable: true }
|
||
title: { type: string }
|
||
content: { type: string }
|
||
tags: { type: array, items: { type: string } }
|
||
cover_title: { type: string }
|
||
image_brief: { type: string }
|
||
source: { type: string, enum: [ai, import] }
|
||
score: { $ref: '#/components/schemas/TextCandidateScore' }
|
||
banned_word_status: { type: string, enum: [pass, auto_fixed, soft_warn, hard_block] }
|
||
is_selected: { type: boolean }
|
||
verdict: { type: string }
|
||
summary: { type: string }
|
||
edited: { type: boolean }
|
||
|
||
ImageCandidateItem:
|
||
type: object
|
||
properties:
|
||
candidate_id: { type: integer }
|
||
strategy: { type: string, enum: [A, B, C] }
|
||
url: { type: string }
|
||
role:
|
||
type: string
|
||
enum: [hook, pain, proof, quality, credit, convert, main]
|
||
description: "storyboard角色,单张图用main"
|
||
seq: { type: integer }
|
||
is_selected: { type: boolean }
|
||
is_regen: { type: boolean }
|
||
ai_visual_score: { type: number, nullable: true }
|
||
ai_visual_note: { type: string, nullable: true }
|
||
|
||
SelectCandidateRequest:
|
||
type: object
|
||
required: [candidate_id]
|
||
properties:
|
||
candidate_id: { type: integer }
|
||
|
||
ImportTextRequest:
|
||
type: object
|
||
required: [content, angle_label]
|
||
properties:
|
||
content: { type: string }
|
||
angle_label: { type: string }
|
||
|
||
RejectRequest:
|
||
type: object
|
||
required: [reason]
|
||
properties:
|
||
reason: { type: string, description: "原文存 preference_events.reason,不做AI归纳" }
|
||
|
||
PreferenceContextData:
|
||
type: object
|
||
properties:
|
||
recent_preference: { type: string, example: "偏好痛点切入角度(已选3次)" }
|
||
reject_reasons: { type: array, items: { type: string }, maxItems: 3 }
|
||
injected_count: { type: integer }
|
||
|
||
ReviewQueueItem:
|
||
type: object
|
||
properties:
|
||
task_id: { type: integer }
|
||
product_name: { type: string }
|
||
theme: { type: string }
|
||
submitted_at: { type: string, format: date-time }
|
||
operator_name: { type: string }
|
||
selected_text:
|
||
allOf:
|
||
- $ref: '#/components/schemas/TextCandidateItem'
|
||
nullable: true
|
||
selected_image:
|
||
allOf:
|
||
- $ref: '#/components/schemas/ImageCandidateItem'
|
||
nullable: true
|
||
selected_sets:
|
||
type: array
|
||
items:
|
||
type: object
|
||
properties:
|
||
strategy: { type: string, enum: [A, B, C] }
|
||
selected_text:
|
||
allOf:
|
||
- $ref: '#/components/schemas/TextCandidateItem'
|
||
nullable: true
|
||
selected_images:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/ImageCandidateItem'
|
||
|
||
PackageRequest:
|
||
type: object
|
||
properties:
|
||
note_ids: { type: array, items: { type: integer } }
|
||
|
||
DeliveryPackageData:
|
||
type: object
|
||
properties:
|
||
id: { type: integer }
|
||
status: { type: string, enum: [pending, ready, downloaded] }
|
||
download_url: { type: string, nullable: true }
|
||
expires_at: { type: string, format: date-time, nullable: true }
|
||
|
||
paths:
|
||
# ── 认证 ──
|
||
/auth/login:
|
||
post:
|
||
summary: 登录获取JWT
|
||
security: []
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/LoginRequest' }
|
||
responses:
|
||
"200":
|
||
description: 登录成功
|
||
content:
|
||
application/json:
|
||
schema:
|
||
allOf:
|
||
- $ref: '#/components/schemas/SuccessEnvelope'
|
||
- properties:
|
||
data: { $ref: '#/components/schemas/LoginData' }
|
||
|
||
/auth/change-password:
|
||
post:
|
||
summary: 修改当前登录用户密码(首登强制改密)
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/ChangePasswordRequest' }
|
||
responses:
|
||
"200": { description: OK }
|
||
|
||
/auth/me:
|
||
get:
|
||
summary: 当前用户信息
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema:
|
||
allOf:
|
||
- $ref: '#/components/schemas/SuccessEnvelope'
|
||
- properties:
|
||
data: { $ref: '#/components/schemas/MeData' }
|
||
|
||
/workspaces/switch:
|
||
post:
|
||
summary: 切换workspace(查membership)
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/SwitchWorkspaceRequest' }
|
||
responses:
|
||
"200":
|
||
description: 切换成功
|
||
content:
|
||
application/json:
|
||
schema:
|
||
allOf:
|
||
- $ref: '#/components/schemas/SuccessEnvelope'
|
||
- properties:
|
||
data: { $ref: '#/components/schemas/SwitchWorkspaceData' }
|
||
|
||
# ── API Key ──
|
||
/api-keys:
|
||
get:
|
||
summary: 列出API Key(只显provider+后4位)
|
||
responses:
|
||
"200": { description: OK }
|
||
post:
|
||
summary: 录入API Key(Fernet加密存储)
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/ApiKeyCreateRequest' }
|
||
responses:
|
||
"200": { description: OK }
|
||
|
||
/api-keys/{id}:
|
||
delete:
|
||
summary: 删除API Key
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
responses:
|
||
"200": { description: OK }
|
||
|
||
# ── 品牌库 ──
|
||
/products:
|
||
get:
|
||
summary: 产品档案列表
|
||
responses:
|
||
"200": { description: OK }
|
||
post:
|
||
summary: 新建产品档案
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/ProductCreateRequest' }
|
||
responses:
|
||
"200": { description: OK }
|
||
|
||
/products/{id}:
|
||
get:
|
||
summary: 产品详情
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
responses:
|
||
"200": { description: OK }
|
||
put:
|
||
summary: 更新产品档案
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/ProductCreateRequest' }
|
||
responses:
|
||
"200": { description: OK }
|
||
delete:
|
||
summary: 删除产品档案
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
responses:
|
||
"200": { description: OK }
|
||
|
||
/products/{id}/benchmarks:
|
||
get:
|
||
summary: 标杆笔记列表
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
responses:
|
||
"200": { description: OK }
|
||
post:
|
||
summary: 新增标杆笔记(JSON兼容接口;外部链接存 link_url,不上传截图)
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/BenchmarkCreateRequest' }
|
||
responses:
|
||
"200": { description: OK }
|
||
|
||
/products/{id}/benchmarks/upload:
|
||
post:
|
||
summary: 上传标杆笔记(原始链接 + 截图文件 + 手填亮点)
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
multipart/form-data:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
screenshot:
|
||
type: string
|
||
format: binary
|
||
description: JPEG/PNG/WebP,最大 10MB,用于视觉分析
|
||
highlights:
|
||
type: string
|
||
description: 手填亮点,可选
|
||
link_url:
|
||
type: string
|
||
description: 小红书或外部原始链接,可选,必须 http/https
|
||
responses:
|
||
"200": { description: OK }
|
||
|
||
/benchmarks/{id}/analyze:
|
||
post:
|
||
summary: 分析标杆笔记(截图视觉分析 + 原始链接/亮点上下文)
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
code: { type: integer }
|
||
message: { type: string }
|
||
data: { $ref: '#/components/schemas/BenchmarkItem' }
|
||
|
||
# ── 违禁词 ──
|
||
/banned-words:
|
||
get:
|
||
summary: 违禁词库列表
|
||
responses:
|
||
"200": { description: OK }
|
||
post:
|
||
summary: 新增违禁词
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/BannedWordRequest' }
|
||
responses:
|
||
"200": { description: OK }
|
||
|
||
/banned-words/{id}:
|
||
put:
|
||
summary: 更新违禁词
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/BannedWordRequest' }
|
||
responses:
|
||
"200": { description: OK }
|
||
delete:
|
||
summary: 删除违禁词
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
responses:
|
||
"200": { description: OK }
|
||
|
||
# ── 生产链 ──
|
||
/tasks:
|
||
get:
|
||
summary: 任务列表(可按status筛选)
|
||
parameters:
|
||
- in: query
|
||
name: status
|
||
schema: { type: string }
|
||
- in: query
|
||
name: page
|
||
schema: { type: integer, default: 1 }
|
||
- in: query
|
||
name: page_size
|
||
schema: { type: integer, default: 20 }
|
||
responses:
|
||
"200": { description: OK }
|
||
post:
|
||
summary: 发起生产任务(校验key→只推task_id入Celery队列)
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/TaskCreateRequest' }
|
||
responses:
|
||
"200": { description: OK }
|
||
"422":
|
||
description: 未配API Key或违禁词硬拦截
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/ErrorEnvelope' }
|
||
|
||
/tasks/{id}:
|
||
get:
|
||
summary: 任务详情(含候选+状态机当前态)
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
responses:
|
||
"200": { description: OK }
|
||
|
||
/tasks/{id}/sse-ticket:
|
||
post:
|
||
summary: 签发一次性 SSE ticket(60s有效,换票后立即建 EventSource)
|
||
description: "安全红线:SSE 不传 JWT 进 URL,先换 ticket 再连流。"
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
ticket: { type: string }
|
||
expires_in: { type: integer, example: 60 }
|
||
|
||
/tasks/{id}/stream:
|
||
get:
|
||
summary: SSE实时进度(ticket认证,断线重连后端补发历史事件)
|
||
description: "用 ?ticket= 一次性短票认证,禁止 ?token= 直传 JWT。"
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
- in: query
|
||
name: ticket
|
||
required: true
|
||
schema: { type: string }
|
||
- in: query
|
||
name: last_seq
|
||
required: false
|
||
schema: { type: integer, default: 0 }
|
||
responses:
|
||
"200":
|
||
description: SSE流
|
||
content:
|
||
text/event-stream:
|
||
schema: { type: string }
|
||
|
||
/tasks/{id}/text-candidates/select:
|
||
post:
|
||
summary: 选文案(飞轮入口1,+3分)
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/SelectCandidateRequest' }
|
||
responses:
|
||
"200": { description: OK }
|
||
|
||
/tasks/{id}/image-candidates/select:
|
||
post:
|
||
summary: 选图(飞轮入口2,+3分)
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/SelectCandidateRequest' }
|
||
responses:
|
||
"200": { description: OK }
|
||
|
||
/tasks/{id}/import-text:
|
||
post:
|
||
summary: 轨B:导入外部文案直接进候选池(跳过AI生成)
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/ImportTextRequest' }
|
||
responses:
|
||
"200": { description: OK }
|
||
|
||
/tasks/{id}/regenerate:
|
||
post:
|
||
summary: 重新生成(飞轮-1分)
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
responses:
|
||
"200": { description: OK }
|
||
|
||
/tasks/{id}/submit-review:
|
||
post:
|
||
summary: 提交审核(状态→pending_review)
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
responses:
|
||
"200": { description: OK }
|
||
|
||
/tasks/{id}/preference/context:
|
||
get:
|
||
summary: 取飞轮偏好上下文(供前端显示"本次已注入"摘要)
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema:
|
||
allOf:
|
||
- $ref: '#/components/schemas/SuccessEnvelope'
|
||
- properties:
|
||
data: { $ref: '#/components/schemas/PreferenceContextData' }
|
||
|
||
# ── 审核 ──
|
||
/review/queue:
|
||
get:
|
||
summary: 待审队列(组长视角)
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema:
|
||
allOf:
|
||
- $ref: '#/components/schemas/SuccessEnvelope'
|
||
- properties:
|
||
data:
|
||
type: object
|
||
properties:
|
||
items:
|
||
type: array
|
||
items: { $ref: '#/components/schemas/ReviewQueueItem' }
|
||
|
||
/review/{task_id}/approve:
|
||
post:
|
||
summary: 审核通过(飞轮+5,状态→approved)
|
||
parameters:
|
||
- in: path
|
||
name: task_id
|
||
required: true
|
||
schema: { type: integer }
|
||
responses:
|
||
"200": { description: OK }
|
||
|
||
/review/{task_id}/reject:
|
||
post:
|
||
summary: 打回(写原因,-3,回pending_selection,原因下次注入prompt)
|
||
parameters:
|
||
- in: path
|
||
name: task_id
|
||
required: true
|
||
schema: { type: integer }
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/RejectRequest' }
|
||
responses:
|
||
"200": { description: OK }
|
||
|
||
# ── 交付包 ──
|
||
/tasks/{id}/package:
|
||
post:
|
||
summary: 生成达人素材交付包(去水印+打包)
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
requestBody:
|
||
content:
|
||
application/json:
|
||
schema: { $ref: '#/components/schemas/PackageRequest' }
|
||
responses:
|
||
"200": { description: OK }
|
||
|
||
/delivery-packages/{id}/download:
|
||
get:
|
||
summary: 查询交付包状态(GET只读,无副作用)
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema:
|
||
allOf:
|
||
- $ref: '#/components/schemas/SuccessEnvelope'
|
||
- properties:
|
||
data: { $ref: '#/components/schemas/DeliveryPackageData' }
|
||
|
||
/delivery-packages/{id}/mark-downloaded:
|
||
post:
|
||
summary: 显式标记交付包已下载
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
responses:
|
||
"200":
|
||
description: OK
|
||
content:
|
||
application/json:
|
||
schema:
|
||
allOf:
|
||
- $ref: '#/components/schemas/SuccessEnvelope'
|
||
- properties:
|
||
data: { $ref: '#/components/schemas/DeliveryPackageData' }
|
||
|
||
/delivery-packages/{id}/download-file:
|
||
get:
|
||
summary: 下载交付包 zip 文件(GET只读)
|
||
parameters:
|
||
- in: path
|
||
name: id
|
||
required: true
|
||
schema: { type: integer }
|
||
responses:
|
||
"200": { description: ZIP 文件 }
|
||
|
||
# SSE事件约定见 启动包/API契约.md §2
|
||
# 二期端点(注册/矩阵号/管理后台)不在此文件中定义
|