Files
lai_hong 1f9eb2853c
Build, Push and Deploy / build (push) Successful in 12s
Build, Push and Deploy / deploy (push) Successful in 25s
fix(export): outline SVG text for AI export
2026-09-13 15:55:46 +08:00

376 lines
8.4 KiB
Markdown
Raw Permalink 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 说明
本文档按 `backend/service/app.py``backend/service/schemas.py` 当前代码整理。
## 基础约定
- 默认后端地址:`http://localhost:8000`
- 请求体中上传文件使用 `multipart/form-data`
- `params` 字段是 JSON 字符串,顶层必须是对象
- 任务状态存在内存中(`JobManager`),服务重启后状态会丢失;文件仍保留在 `service_workspace`
- CORS 已开启,允许所有来源
## Jobs
### GET `/api/health`
健康检查。
```json
{"ok": true}
```
### GET `/api/jobs`
返回任务状态列表,最新任务在前。除内存中登记的任务外,还会扫描 `service_workspace` 补充磁盘上已完成但未登记的任务(有 `wordcloud_hd.db` 即认为是成功可查找)。
### POST `/api/jobs`
创建词云任务。
Form 字段:
| 字段 | 必填 | 说明 |
|------|------|------|
| `name_list` | 是 | `.xlsx` 名单文件 |
| `mask_image` | IMAGE 模式必填 | `.png` / `.jpg` / `.jpeg` 掩膜 |
| `font_file` | 否 | 临时上传字体(`.ttf` / `.ttc` / `.otf` |
| `font_id` | 否 | 使用已上传字体 |
| `params` | 否 | JSON 字符串,合并到任务配置 |
`params` 示例:
```json
{
"MODE": "IMAGE",
"DATA_COL_INDEX": 1,
"SEED": 42,
"N_REPETITIONS": 20,
"ENABLE_STROKE_WEIGHTS": false,
"FONT_COLOR": "#000000"
}
```
响应:
```json
{"job_id": "..." }
```
### GET `/api/jobs/{job_id}`
返回 `JobStatus`
```json
{
"job_id": "...",
"status": "queued|running|success|failed",
"stage": "...",
"progress_percent": 0,
"message": "...",
"created_at": "...",
"updated_at": "...",
"artifacts": {},
"error": ""
}
```
### GET `/api/jobs/{job_id}/detail`
返回状态和最近事件:
```json
{
"status": {},
"recent_events": []
}
```
### GET `/api/jobs/{job_id}/events`
SSE 事件流。事件数据模型:
```json
{
"type": "log|status",
"stage": "placing_words",
"progress_percent": 65,
"message": "...",
"timestamp": "..."
}
```
### GET `/api/jobs/{job_id}/result`
返回可下载产物 URL
```json
{
"job_id": "...",
"status": "success",
"image_url": "/api/jobs/{job_id}/files/png",
"svg_url": "/api/jobs/{job_id}/files/svg",
"svg_stroke_url": "/api/jobs/{job_id}/files/svg_stroke",
"db_url": "/api/jobs/{job_id}/files/db",
"metrics_url": "/api/jobs/{job_id}/files/metrics"
}
```
### GET `/api/jobs/{job_id}/files/{kind}`
下载产物。`kind` 支持:
- `png`
- `svg`
- `svg_stroke`
- `db`
- `metrics`
### GET `/api/jobs/{job_id}/locations`
查询词语位置(单任务内查找)。
查询参数:
| 参数 | 说明 |
|------|------|
| `name` | 可选;为空返回全部,非空时按 `mode` 匹配 |
| `mode` | 可选;`exact`(默认,精确匹配)/ `contains`(子串包含,转义通配符后 `LIKE %name%` |
返回:
```json
{
"job_id": "...",
"query": "",
"mode": "exact",
"total": 1,
"canvas_width": 8000,
"canvas_height": 4000,
"matches": [
{
"id": 1,
"name": "张三",
"x": 100,
"y": 200,
"font_size": 64,
"color": "#000000",
"orientation": "horizontal",
"box_x": 100,
"box_y": 200,
"box_width": 120,
"box_height": 50
}
]
}
```
### GET `/api/jobs/{job_id}/find`
单任务内查找名字的**受保护接口**,供独立查找页使用(与 `/locations` 响应结构相同)。
- 需要鉴权:`Authorization: Bearer <token>`token 由 `POST /api/login` 获取
- 查询参数与 `/locations` 一致:`name``mode``exact` / `contains`
- 无 token 或 token 错误返回 `403`
### POST `/api/login`
管理口令登录,返回查找页 / 订单页共用的鉴权 token。
请求体(JSON):
```json
{"password": "管理口令"}
```
- 口令错误返回 `401`
- 成功返回:`{"token": "..."}`;后续请求带 `Authorization: Bearer <token>`
- 默认口令 `zhihui2024`,生产可用环境变量 `ORDERS_ADMIN_PASSWORD` 覆盖(见 `backend/service/app.py`
### GET `/api/jobs/{job_id}/occupancy_mask`
返回 PNG,显示每个已放置词语的 bounding box。
### GET `/api/jobs/{job_id}/custom.svg`
按已生成 DB 重新导出 SVG。
查询参数:
| 参数 | 默认 | 说明 |
|------|------|------|
| `fill` | `fill` | `fill` / `dot` / `line` / `ring` |
| `stroke` | `0` | 是否描边 |
| `spacing` | `10` | 点阵间距 |
| `radius` | `2` | 点阵半径 |
| `color` | `#000000` | 输出颜色 |
| `line_spacing` | `6` | 线填充间距 |
| `line_width` | `1` | 线宽 |
| `line_angle` | `0` | 线角度 |
| `ring_radius` | `3` | 环半径 |
| `ring_width` | `1` | 环线宽 |
| `ring_spacing` | `8` | 环间距 |
### POST `/api/exports/ai`
将应用生成的 SVG 转换为 Illustrator 5 兼容的 `.ai` 文件。该接口仅转发到 Compose 内部的 `ai-converter` 服务,不暴露转换容器端口。
请求体:
```json
{
"svg": "<svg ...>...</svg>",
"filename": "wordcloud.ai"
}
```
- 最大 SVG 大小:25 MB。
- 当前支持路径、`rect``circle``ellipse``line`、纯色填充/描边和仿射变换。
- 普通 SVG `text` 会先使用内置中文字体转换为轮廓路径,以保证中文在 AI 中可见;文本将不再是可编辑文字。
- 不支持图片、SVG 图案/裁剪/透明效果时会返回 `422`,不会产生可能失真的 AI 文件。
## Templates
### GET `/api/templates`
返回后端硬编码模板列表:
- `poster_1x2`(竖版手机海报,1080×2160
- `poster_4x5`(社交媒体图,1080×1350
- `poster_1x1`(方形封面,1080×1080
- `poster_3x4`(竖版广告,1080×1440
- `poster_16x9`(横版电商,1920×1080
## Assets
### POST `/api/assets`
上传素材。Form 字段:
| 字段 | 必填 | 说明 |
|------|------|------|
| `file` | 是 | 素材文件 |
| `name` | 否 | 名称 |
| `type` | 否 | 默认 `upload` |
### POST `/api/assets/from-job/{job_id}`
从任务产物导入素材。Form 字段:
| 字段 | 默认 | 说明 |
|------|------|------|
| `kind` | `png` | 产物类型 |
| `name` | 空 | 素材名称 |
| `type` | `wordcloud` | 素材类型 |
### GET `/api/assets`
列出素材。支持查询参数:
- `type`
- `job_id`
### GET `/api/assets/{asset_id}`
获取素材元数据。
### GET `/api/assets/{asset_id}/download`
下载素材文件。
### DELETE `/api/assets/{asset_id}`
删除素材。
## Projects
### POST `/api/projects`
创建工程。Form 字段:
| 字段 | 必填 | 说明 |
|------|------|------|
| `name` | 是 | 工程名 |
| `template_id` | 是 | 模板 ID |
| `background_color` | 是 | `#RRGGBB` |
| `stickers` | 否 | JSON 数组字符串 |
### GET `/api/projects`
返回工程摘要列表。
### GET `/api/projects/{project_id}`
返回工程完整数据。
### PATCH `/api/projects/{project_id}`
按传入 Form 字段部分更新工程。
### DELETE `/api/projects/{project_id}`
删除工程。
## Fonts
### GET `/api/fonts`
返回字体列表,包含默认字体项(`__default__`)。
### POST `/api/fonts`
上传字体。Form 字段:
| 字段 | 必填 | 说明 |
|------|------|------|
| `file` | 是 | 字体文件(`.ttf` / `.ttc` / `.otf` |
| `name` | 否 | 字体名 |
### DELETE `/api/fonts/{font_id}`
删除已上传字体。默认字体不能删除。
## Line Spacing Analysis
### POST `/api/jobs/{job_id}/analyze-line-spacing`
分析 SVG 词云路径的线距,返回 `LineSpacingAnalysisSummary`
请求体(JSON):
```json
{
"percentile": 3,
"elementWidth": 100.0,
"elementHeight": 100.0,
"sampleStep": 2.0
}
```
响应字段:
| 字段 | 说明 |
|------|------|
| `percentile` | 线距百分位 |
| `spacingPx` | 采样线距(像素) |
| `spacingMm` | 采样线距(毫米) |
| `minSpacingPx` | 最小线距(像素) |
| `minSpacingMm` | 最小线距(毫米) |
| `curveCount` | 曲线数量 |
| `segmentCount` | 线段数量 |
| `sourceWidth` / `sourceHeight` | SVG 原始尺寸 |
| `elementWidth` / `elementHeight` | 目标元素尺寸 |
## 常见错误
| 场景 | 状态码 | detail |
|------|--------|--------|
| `params` 不是合法 JSON | 400 | `params must be valid JSON` |
| `params` 不是对象 | 400 | `params must be JSON object` |
| `name_list``.xlsx` | 400 | `name_list must be xlsx` |
| IMAGE 模式缺少掩膜 | 400 | `mask_image is required when MODE=IMAGE` |
| 掩膜文件不存在 | 400 | `mask_image must be png/jpg/jpeg` |
| job 不存在 | 404 | `job not found` |
| 产物未就绪 | 404 | `artifact not ready` |
| 文件类型未知 | 404 | `unknown artifact kind` |