Generated plan.md, research.md, data-model.md, contracts/api.md, quickstart.md, and CLAUDE.md agent context via /speckit-plan.
7.4 KiB
7.4 KiB
API Contract: AI 服务接口定义
Branch: 001-ai-service-requirements | Date: 2026-04-10
Base URL: http://ai-service:8000
API Prefix: /api/v1
Swagger: /docs(FastAPI 自动生成)
通用约定
请求格式
- 所有请求体:
Content-Type: application/json - 无认证机制(内网服务,仅 Java 后端调用)
响应格式
- 成功:HTTP 2xx,JSON 响应体
- 错误:HTTP 4xx/5xx,统一错误格式:
{"code": "ERROR_CODE", "message": "具体描述"}
错误码
| HTTP 状态码 | code | 触发条件 |
|---|---|---|
| 400 | UNSUPPORTED_FILE_TYPE | 文件格式不支持(如 .xlsx) |
| 400 | VIDEO_TOO_LARGE | 视频文件超过大小上限 |
| 502 | STORAGE_ERROR | RustFS 不可达或文件不存在 |
| 502 | LLM_PARSE_ERROR | GLM 返回非合法 JSON |
| 503 | LLM_CALL_ERROR | GLM API 限流 / 超时 |
| 500 | INTERNAL_ERROR | 未捕获异常 |
端点一览
| 端点 | 方法 | 功能 | 响应码 |
|---|---|---|---|
/health |
GET | 健康检查 | 200 |
/api/v1/text/extract |
POST | 文档三元组提取 | 200 |
/api/v1/image/extract |
POST | 图像四元组提取 | 200 |
/api/v1/video/extract-frames |
POST | 视频帧提取(异步) | 202 |
/api/v1/video/to-text |
POST | 视频转文本(异步) | 202 |
/api/v1/qa/gen-text |
POST | 文本问答对生成 | 200 |
/api/v1/qa/gen-image |
POST | 图像问答对生成 | 200 |
/api/v1/finetune/start |
POST | 提交微调任务 | 200 |
/api/v1/finetune/status/{jobId} |
GET | 查询微调状态 | 200 |
端点详情
GET /health
健康检查端点,无需认证,无请求体。
响应(200 OK):
{"status": "ok"}
POST /api/v1/text/extract
从存储中指定路径的文档提取文本三元组。
请求体:
{
"file_path": "text/202404/123.txt",
"file_name": "设备规范.txt",
"model": "glm-4-flash",
"prompt_template": "..."
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| file_path | string | 是 | RustFS 中的文件路径 |
| file_name | string | 是 | 带扩展名的文件名(用于判断格式) |
| model | string | 否 | 模型名,默认使用 config 中的 default_text |
| prompt_template | string | 否 | 自定义提示词,不传使用内置模板 |
支持格式: .txt, .pdf, .docx
响应(200 OK):
{
"items": [
{
"subject": "变压器",
"predicate": "额定电压",
"object": "110kV",
"source_snippet": "该变压器额定电压为110kV",
"source_offset": {"start": 120, "end": 150}
}
]
}
POST /api/v1/image/extract
从存储中指定路径的图片提取知识四元组,并自动裁剪 bbox 区域。
请求体:
{
"file_path": "image/202404/456.jpg",
"task_id": 789,
"model": "glm-4v-flash",
"prompt_template": "..."
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| file_path | string | 是 | RustFS 中的图片路径 |
| task_id | int | 是 | 标注任务 ID(用于构造裁剪图存储路径) |
| model | string | 否 | 默认使用 config 中的 default_vision |
| prompt_template | string | 否 | 自定义提示词 |
响应(200 OK):
{
"items": [
{
"subject": "电缆接头",
"predicate": "位于",
"object": "配电箱左侧",
"qualifier": "2024年检修现场",
"bbox": {"x": 10, "y": 20, "w": 100, "h": 80},
"cropped_image_path": "crops/789/0.jpg"
}
]
}
POST /api/v1/video/extract-frames
触发视频帧提取后台任务,立即返回。
请求体:
{
"file_path": "video/202404/001.mp4",
"source_id": 10,
"job_id": 42,
"mode": "interval",
"frame_interval": 30
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| file_path | string | 是 | RustFS 中的视频路径 |
| source_id | int | 是 | 原始资料 ID(用于构造帧存储路径) |
| job_id | int | 是 | 由 Java 后端分配的任务 ID |
| mode | string | 否 | interval(默认)或 keyframe |
| frame_interval | int | 否 | interval 模式专用,按帧数步进,默认 30 |
响应(202 Accepted):
{"message": "任务已接受,后台处理中", "job_id": 42}
完成后回调 Java 后端(POST {BACKEND_CALLBACK_URL}):
{
"job_id": 42,
"status": "SUCCESS",
"frames": [
{"frame_index": 0, "time_sec": 0.0, "frame_path": "frames/10/0.jpg"}
],
"error_message": null
}
POST /api/v1/video/to-text
触发视频片段转文字后台任务,立即返回。
请求体:
{
"file_path": "video/202404/001.mp4",
"source_id": 10,
"job_id": 43,
"start_sec": 0,
"end_sec": 120,
"model": "glm-4v-flash",
"prompt_template": "..."
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| file_path | string | 是 | RustFS 中的视频路径 |
| source_id | int | 是 | 原始资料 ID |
| job_id | int | 是 | 由 Java 后端分配的任务 ID |
| start_sec | float | 是 | 分析起始时间(秒) |
| end_sec | float | 是 | 分析结束时间(秒) |
| model | string | 否 | 默认使用 config 中的 default_vision |
| prompt_template | string | 否 | 自定义提示词 |
响应(202 Accepted):
{"message": "任务已接受,后台处理中", "job_id": 43}
完成后回调 Java 后端(POST {BACKEND_CALLBACK_URL}):
{
"job_id": 43,
"status": "SUCCESS",
"output_path": "video-text/10/1712800000.txt",
"error_message": null
}
POST /api/v1/qa/gen-text
基于文本三元组批量生成候选问答对。
请求体:
{
"items": [
{
"subject": "变压器",
"predicate": "额定电压",
"object": "110kV",
"source_snippet": "该变压器额定电压为110kV"
}
],
"model": "glm-4-flash",
"prompt_template": "..."
}
响应(200 OK):
{
"pairs": [
{"question": "变压器的额定电压是多少?", "answer": "该变压器额定电压为110kV。"}
]
}
POST /api/v1/qa/gen-image
基于图像四元组生成候选图文问答对。图片由 AI 服务从存储自动获取,调用方只需提供路径。
请求体:
{
"items": [
{
"subject": "电缆接头",
"predicate": "位于",
"object": "配电箱左侧",
"qualifier": "2024年检修现场",
"cropped_image_path": "crops/789/0.jpg"
}
],
"model": "glm-4v-flash",
"prompt_template": "..."
}
响应(200 OK):
{
"pairs": [
{
"question": "图中电缆接头位于何处?",
"answer": "图中电缆接头位于配电箱左侧。",
"image_path": "crops/789/0.jpg"
}
]
}
POST /api/v1/finetune/start
向 ZhipuAI 提交微调任务。
请求体:
{
"jsonl_url": "https://rustfs.example.com/finetune-export/export/xxx.jsonl",
"base_model": "glm-4-flash",
"hyperparams": {"learning_rate": 1e-4, "epochs": 3}
}
响应(200 OK):
{"job_id": "glm-ft-xxxxxx"}
GET /api/v1/finetune/status/{jobId}
查询微调任务状态。
路径参数: jobId — 微调任务 ID(由 /finetune/start 返回)
响应(200 OK):
{
"job_id": "glm-ft-xxxxxx",
"status": "RUNNING",
"progress": 45,
"error_message": null
}
status 取值: RUNNING | SUCCESS | FAILED