该文件提供场景模块相关的接口,包括:
部分接口需要 Token 认证,部分接口为公开接口。
路由前缀:/apiv1(以 routers/__init__.py 中注册为准)
/apiv1/get_scene_list — 获取场景列表功能说明: 查询所有未删除的场景(顶级分类)。
是否需要认证: 否
请求方式: GET
请求参数: 无
成功响应字段: | 字段 | 类型 | 说明 | |------|------|------| | data[].id | int | 场景 ID | | data[].scene_name | string | 场景名称(中文) | | data[].scene_en_name | string | 场景英文名称 |
测试用例:
// 请求
GET /apiv1/get_scene_list
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": [
{
"id": 1,
"scene_name": "隧道施工",
"scene_en_name": "tunnel_construction"
},
{
"id": 2,
"scene_name": "桥梁施工",
"scene_en_name": "bridge_construction"
}
]
}
// 请求
GET /apiv1/get_scene_list
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": []
}
/apiv1/get_first_scene_list — 获取一级场景列表功能说明: 根据场景 ID 查询对应的一级场景列表。
是否需要认证: 否
请求方式: GET
请求参数(Query): | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | scene_id | int | 是 | 场景 ID |
成功响应字段: | 字段 | 类型 | 说明 | |------|------|------| | data[].id | int | 一级场景 ID | | data[].first_scene_name | string | 一级场景名称 |
测试用例:
// 请求
GET /apiv1/get_first_scene_list?scene_id=1
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": [
{"id": 1, "first_scene_name": "开挖作业"},
{"id": 2, "first_scene_name": "支护作业"}
]
}
// 请求
GET /apiv1/get_first_scene_list?scene_id=999
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": []
}
// 请求
GET /apiv1/get_first_scene_list
// 预期响应 (HTTP 422) — FastAPI 参数校验失败
{
"detail": [
{
"loc": ["query", "scene_id"],
"msg": "field required",
"type": "value_error.missing"
}
]
}
/apiv1/get_second_scene_list — 获取二级场景列表功能说明: 根据一级场景 ID 查询对应的二级场景列表。
是否需要认证: 否
请求方式: GET
请求参数(Query): | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | first_scene_id | int | 是 | 一级场景 ID |
成功响应字段: | 字段 | 类型 | 说明 | |------|------|------| | data[].id | int | 二级场景 ID | | data[].second_scene_name | string | 二级场景名称 |
测试用例:
// 请求
GET /apiv1/get_second_scene_list?first_scene_id=1
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": [
{"id": 1, "second_scene_name": "机械开挖"},
{"id": 2, "second_scene_name": "人工开挖"}
]
}
// 请求
GET /apiv1/get_second_scene_list?first_scene_id=999
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": []
}
// 请求
GET /apiv1/get_second_scene_list
// 预期响应 (HTTP 422)
{
"detail": [
{
"loc": ["query", "first_scene_id"],
"msg": "field required",
"type": "value_error.missing"
}
]
}
/apiv1/get_third_scene_list — 获取三级场景列表功能说明: 根据二级场景 ID 查询对应的三级场景列表,包含正确和错误示例图。
是否需要认证: 否
请求方式: GET
请求参数(Query): | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | second_scene_id | int | 是 | 二级场景 ID |
成功响应字段: | 字段 | 类型 | 说明 | |------|------|------| | data[].id | int | 三级场景 ID | | data[].third_scene_name | string | 三级场景名称 | | data[].correct_example_image | string | 正确示例图 URL | | data[].wrong_example_image | string | 错误示例图 URL |
测试用例:
// 请求
GET /apiv1/get_third_scene_list?second_scene_id=1
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": [
{
"id": 1,
"third_scene_name": "未佩戴安全帽",
"correct_example_image": "https://oss.example.com/correct_helmet.jpg",
"wrong_example_image": "https://oss.example.com/wrong_helmet.jpg"
}
]
}
// 请求
GET /apiv1/get_third_scene_list?second_scene_id=999
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": []
}
// 请求
GET /apiv1/get_third_scene_list
// 预期响应 (HTTP 422)
{
"detail": [
{
"loc": ["query", "second_scene_id"],
"msg": "field required",
"type": "value_error.missing"
}
]
}
/apiv1/get_third_scene_example_image — 获取三级场景示例图功能说明: 通过三级场景名称查询该场景的正确/错误示例图。
是否需要认证: 否
请求方式: GET
请求参数(Query): | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | third_scene_name | string | 是 | 三级场景名称 |
测试用例:
// 请求
GET /apiv1/get_third_scene_example_image?third_scene_name=未佩戴安全帽
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": {
"id": 1,
"third_scene_name": "未佩戴安全帽",
"correct_example_image": "https://oss.example.com/correct_helmet.jpg",
"wrong_example_image": "https://oss.example.com/wrong_helmet.jpg"
}
}
// 请求
GET /apiv1/get_third_scene_example_image?third_scene_name=不存在的场景
// 预期响应 (HTTP 200, 业务码 404)
{
"statusCode": 404,
"msg": "三级场景不存在"
}
// 请求
GET /apiv1/get_third_scene_example_image?third_scene_name=
// 预期响应 (HTTP 200, 业务码 400)
{
"statusCode": 400,
"msg": "三级场景名称不能为空"
}
// 请求
GET /apiv1/get_third_scene_example_image
// 预期响应 (HTTP 422) — FastAPI 参数校验
{
"detail": [
{
"loc": ["query", "third_scene_name"],
"msg": "field required",
"type": "value_error.missing"
}
]
}
/apiv1/get_history_recognition_record — 获取隐患识别历史记录功能说明: 查询当前用户的所有隐患识别历史记录,按更新时间倒序排列。返回所有记录(不分页)。
是否需要认证: 是
请求方式: GET
请求参数: 无
成功响应字段: | 字段 | 类型 | 说明 | |------|------|------| | data[].id | int | 记录 ID | | data[].title | string | 标题 | | data[].original_image_url | string | 原始图片 URL | | data[].recognition_image_url | string | 识别结果图片 URL | | data[].labels | string | 标签 | | data[].created_at | int | 创建时间(Unix 时间戳) | | total | int | 总记录数 |
测试用例:
// 请求
GET /apiv1/get_history_recognition_record
token: <有效Token>
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": [
{
"id": 5,
"title": "隧道口安全检查",
"original_image_url": "https://oss.example.com/original.jpg",
"recognition_image_url": "https://oss.example.com/result.jpg",
"labels": "未佩戴安全帽,未穿反光衣",
"created_at": 1700000000
}
],
"total": 1
}
// 请求
GET /apiv1/get_history_recognition_record
token: <有效Token>
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": [],
"total": 0
}
// 请求
GET /apiv1/get_history_recognition_record
// 预期响应 (HTTP 200, 业务码 401)
{
"statusCode": 401,
"msg": "未授权"
}
/apiv1/get_recognition_record_detail — 获取识别记录详情功能说明: 通过记录 ID 查询识别记录的完整详情。description 字段会按空格分割为 third_scenes 数组返回。
注意: 该接口未检查用户认证,任何人可通过 ID 查看。
是否需要认证: 否(代码中未做认证校验)
请求方式: GET
请求参数(Query): | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | recognition_id | int | 是 | 识别记录 ID |
成功响应字段: | 字段 | 类型 | 说明 | |------|------|------| | data.id | int | 记录 ID | | data.user_id | int | 用户 ID | | data.title | string | 标题 | | data.description | string | 描述(原始字符串) | | data.original_image_url | string | 原始图片 URL | | data.recognition_image_url | string | 识别结果图片 URL | | data.labels | string | 标签 | | data.third_scenes | array | 三级场景数组(description 按空格分割) | | data.tag_type | string | 标签类型 | | data.scene_match | int/null | 场景匹配评分 | | data.tip_accuracy | int/null | 提示准确度评分 | | data.effect_evaluation | int/null | 效果评价评分 | | data.user_remark | string/null | 用户备注 | | data.created_at | int | 创建时间 | | data.updated_at | int | 更新时间 |
测试用例:
// 请求
GET /apiv1/get_recognition_record_detail?recognition_id=5
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": {
"id": 5,
"user_id": 1,
"title": "隧道口安全检查",
"description": "未佩戴安全帽 未穿反光衣",
"original_image_url": "https://oss.example.com/original.jpg",
"recognition_image_url": "https://oss.example.com/result.jpg",
"labels": "未佩戴安全帽,未穿反光衣",
"third_scenes": ["未佩戴安全帽", "未穿反光衣"],
"tag_type": "auto",
"scene_match": 5,
"tip_accuracy": 4,
"effect_evaluation": 3,
"user_remark": "检测结果较为准确",
"created_at": 1700000000,
"updated_at": 1700001000
}
}
// 请求
GET /apiv1/get_recognition_record_detail?recognition_id=99999
// 预期响应 (HTTP 200, 业务码 404)
{
"statusCode": 404,
"msg": "记录不存在"
}
// 请求
GET /apiv1/get_recognition_record_detail?recognition_id=3
// 预期响应 (HTTP 200)
// 当 record.description 为 None 或空字符串时
{
"statusCode": 200,
"msg": "success",
"data": {
"id": 3,
"...": "...",
"description": null,
"third_scenes": [],
"...": "..."
}
}
// 请求
GET /apiv1/get_recognition_record_detail
// 预期响应 (HTTP 422)
{
"detail": [
{
"loc": ["query", "recognition_id"],
"msg": "field required",
"type": "value_error.missing"
}
]
}
/apiv1/delete_recognition_record — 删除识别记录(软删除)功能说明: 软删除指定的识别记录。设置 is_deleted=1 和 deleted_at 为当前时间戳。仅能删除当前用户自己的记录。
是否需要认证: 是
请求方式: POST
请求体(JSON): | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | recognition_id | int | 是 | 识别记录 ID |
业务逻辑:
recognition_id + user_id 条件更新 is_deleted=1, deleted_at=当前时间戳测试用例:
// 请求
POST /apiv1/delete_recognition_record
token: <有效Token>
Content-Type: application/json
{
"recognition_id": 5
}
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "删除成功"
}
// 请求
POST /apiv1/delete_recognition_record
token: <有效Token>
Content-Type: application/json
{
"recognition_id": 99999
}
// 预期响应 (HTTP 200)
// 注意:代码中未检查 update 影响行数,即使没有匹配记录也返回成功
{
"statusCode": 200,
"msg": "删除成功"
}
// 请求
POST /apiv1/delete_recognition_record
// 预期响应 (HTTP 200, 业务码 401)
{
"statusCode": 401,
"msg": "未授权"
}
// 请求
POST /apiv1/delete_recognition_record
token: <有效Token>
Content-Type: application/json
{}
// 预期响应 (HTTP 422)
{
"detail": [
{
"loc": ["body", "recognition_id"],
"msg": "field required",
"type": "value_error.missing"
}
]
}
/apiv1/submit_evaluation — 提交点评功能说明: 对识别记录提交评价,可选评分场景匹配度、提示准确度、效果评价和用户备注。仅更新传入的非 None 字段。
注意: 该接口未检查用户认证,任何人可提交评价。
是否需要认证: 否(代码中未做认证校验)
请求方式: POST
请求体(JSON): | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | id | int | 是 | 识别记录 ID | | scene_match | int | 否 | 场景匹配度评分 | | tip_accuracy | int | 否 | 提示准确度评分 | | effect_evaluation | int | 否 | 效果评价评分 | | user_remark | string | 否 | 用户备注 |
业务逻辑:
id 对应的未删除记录data 中非 None 的字段updated_at 为当前时间戳测试用例:
// 请求
POST /apiv1/submit_evaluation
Content-Type: application/json
{
"id": 5,
"scene_match": 5,
"tip_accuracy": 4,
"effect_evaluation": 3,
"user_remark": "检测较为准确,但有一处漏检"
}
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success"
}
// 请求
POST /apiv1/submit_evaluation
Content-Type: application/json
{
"id": 5,
"effect_evaluation": 4
}
// 预期响应 (HTTP 200)
// 仅 effect_evaluation 和 updated_at 被更新
{
"statusCode": 200,
"msg": "success"
}
// 请求
POST /apiv1/submit_evaluation
Content-Type: application/json
{
"id": 99999,
"scene_match": 5
}
// 预期响应 (HTTP 200, 业务码 404)
{
"statusCode": 404,
"msg": "记录不存在"
}
// 请求
POST /apiv1/submit_evaluation
Content-Type: application/json
{
"scene_match": 5
}
// 预期响应 (HTTP 422)
{
"detail": [
{
"loc": ["body", "id"],
"msg": "field required",
"type": "value_error.missing"
}
]
}
/apiv1/get_latest_recognition_record — 获取最新识别记录功能说明: 获取当前用户的最新一条识别记录。若无记录,返回一个包含 effect_evaluation: 1 的默认数据(给前端使用)。
是否需要认证: 是
请求方式: GET
请求参数: 无
测试用例:
// 请求
GET /apiv1/get_latest_recognition_record
token: <有效Token>
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": {
"id": 10,
"title": "最新检测记录",
"original_image_url": "https://oss.example.com/original.jpg",
"recognition_image_url": "https://oss.example.com/result.jpg",
"labels": "未佩戴安全帽",
"created_at": 1700005000,
"effect_evaluation": 3
}
}
// 请求
GET /apiv1/get_latest_recognition_record
token: <无任何识别记录的用户Token>
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": {
"effect_evaluation": 1
}
}
// 请求
GET /apiv1/get_latest_recognition_record
// 预期响应 (HTTP 200, 业务码 401)
{
"statusCode": 401,
"msg": "未授权"
}
/apiv1/scene_template — 创建场景模板功能说明: 创建一个新的场景模板记录。
注意: 该接口未检查用户认证。
是否需要认证: 否(代码中未做认证校验)
请求方式: POST
请求体(JSON): | 字段 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | scene_name | string | 是 | — | 场景模板名称 | | scene_type | string | 是 | — | 场景类型 | | scene_desc | string | 否 | "" | 场景描述 | | model_name | string | 是 | — | 模型名称 |
业务逻辑:
SceneTemplate 记录,created_at 和 updated_at 设为当前时间戳,is_deleted=0db.refresh(template) 获取自增 ID测试用例:
// 请求
POST /apiv1/scene_template
Content-Type: application/json
{
"scene_name": "隧道口安全检查",
"scene_type": "tunnel",
"scene_desc": "用于检测隧道口作业人员的安全装备佩戴情况",
"model_name": "yolov8-tunnel"
}
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "创建成功",
"data": {
"id": 1
}
}
// 请求
POST /apiv1/scene_template
Content-Type: application/json
{
"scene_name": "桥梁检查",
"scene_type": "bridge",
"model_name": "yolov8-bridge"
}
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "创建成功",
"data": {
"id": 2
}
}
// 请求
POST /apiv1/scene_template
Content-Type: application/json
{
"scene_name": "测试"
}
// 预期响应 (HTTP 422)
{
"detail": [
{
"loc": ["body", "scene_type"],
"msg": "field required",
"type": "value_error.missing"
},
{
"loc": ["body", "model_name"],
"msg": "field required",
"type": "value_error.missing"
}
]
}
/apiv1/scene_templates — 获取场景模板列表功能说明: 分页查询场景模板列表。page_size 最大限制为 100。
注意: 该接口未检查用户认证。
是否需要认证: 否(代码中未做认证校验)
请求方式: GET
请求参数(Query): | 字段 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | page | int | 否 | 1 | 页码 | | page_size | int | 否 | 20 | 每页条数(最大 100) |
成功响应字段: | 字段 | 类型 | 说明 | |------|------|------| | data.total | int | 总记录数 | | data.items[].id | int | 模板 ID | | data.items[].scene_name | string | 场景名称 | | data.items[].scene_type | string | 场景类型 | | data.items[].scene_desc | string | 场景描述 | | data.items[].model_name | string | 模型名称 | | data.items[].created_at | int | 创建时间 |
测试用例:
// 请求
GET /apiv1/scene_templates
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": {
"total": 5,
"items": [
{
"id": 5,
"scene_name": "隧道口安全检查",
"scene_type": "tunnel",
"scene_desc": "检测安全装备佩戴情况",
"model_name": "yolov8-tunnel",
"created_at": 1700005000
}
]
}
}
// 请求
GET /apiv1/scene_templates?page=2&page_size=5
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": {
"total": 12,
"items": [...]
}
}
// 请求
GET /apiv1/scene_templates?page=1&page_size=500
// 预期行为:page_size 被限制为 100,最多返回 100 条记录
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": {
"total": 200,
"items": [...] // 最多 100 条
}
}
// 请求
GET /apiv1/scene_templates
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": {
"total": 0,
"items": []
}
}
/apiv1/recognition_records — 获取识别记录列表(分页+筛选)功能说明: 分页查询当前用户的识别记录,可按场景类型筛选。page_size 最大限制为 100。
是否需要认证: 是
请求方式: GET
请求参数(Query): | 字段 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | scene_type | string | 否 | "" | 场景类型筛选(为空则不筛选) | | page | int | 否 | 1 | 页码 | | page_size | int | 否 | 20 | 每页条数(最大 100) |
成功响应字段: | 字段 | 类型 | 说明 | |------|------|------| | data.total | int | 总记录数 | | data.items[].id | int | 记录 ID | | data.items[].scene_type | string | 场景类型 | | data.items[].original_image_url | string | 原始图片 URL | | data.items[].result_image_url | string | 识别结果图片 URL | | data.items[].hazard_count | int | 隐患数量 | | data.items[].current_step | string | 当前步骤 | | data.items[].created_at | int | 创建时间 |
测试用例:
// 请求
GET /apiv1/recognition_records
token: <有效Token>
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": {
"total": 8,
"items": [
{
"id": 10,
"scene_type": "tunnel",
"original_image_url": "https://oss.example.com/original.jpg",
"result_image_url": "https://oss.example.com/result.jpg",
"hazard_count": 3,
"current_step": "completed",
"created_at": 1700005000
}
]
}
}
// 请求
GET /apiv1/recognition_records?scene_type=tunnel&page=1&page_size=10
token: <有效Token>
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": {
"total": 3,
"items": [...]
}
}
// 请求
GET /apiv1/recognition_records?page=2&page_size=5
token: <有效Token>
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": {
"total": 12,
"items": [...]
}
}
// 请求
GET /apiv1/recognition_records?page=1&page_size=200
token: <有效Token>
// 预期行为:page_size 被限制为 100
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": {
"total": 150,
"items": [...] // 最多 100 条
}
}
// 请求
GET /apiv1/recognition_records
token: <无识别记录的用户Token>
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": {
"total": 0,
"items": []
}
}
// 请求
GET /apiv1/recognition_records
// 预期响应 (HTTP 200, 业务码 401)
{
"statusCode": 401,
"msg": "未授权"
}
| 依赖项 | 说明 |
|---|---|
database.get_db |
SQLAlchemy 数据库会话(Depends 注入) |
models.scene.Scene |
顶级场景模型(字段:id, scene_name, scene_en_name, is_deleted) |
models.scene.FirstScene |
一级场景模型(字段:id, scene_id, first_scene_name, is_deleted) |
models.scene.SecondScene |
二级场景模型(字段:id, first_scene_id, second_scene_name, is_deleted) |
models.scene.ThirdScene |
三级场景模型(字段:id, second_scene_id, third_scene_name, correct_example_image, wrong_example_image, is_deleted) |
models.scene.RecognitionRecord |
识别记录模型(字段:id, user_id, title, description, original_image_url, recognition_image_url, labels, tag_type, scene_match, tip_accuracy, effect_evaluation, user_remark, scene_type, hazard_count, current_step, is_deleted, deleted_at, created_at, updated_at) |
models.scene.SceneTemplate |
场景模板模型(字段:id, scene_name, scene_type, scene_desc, model_name, is_deleted, created_at, updated_at) |
request.state.user |
从中间件注入的用户信息(含 user_id) |
get_recognition_record_detail 和 submit_evaluation 未做用户认证校验, 任何人可通过 ID 查看或评价记录,存在潜在的数据安全风险。delete_recognition_record 不检查记录是否存在, 即使 recognition_id 无效也返回"删除成功"。get_latest_recognition_record 的降级策略: 无记录时返回 {"effect_evaluation": 1} 作为前端默认值,而非空或 404。get_history_recognition_record 查询全量数据(不分页),大量记录时可能存在性能问题。新版接口 recognition_records 已支持分页。description 到 third_scenes 的转换: 在 get_recognition_record_detail 中按空格分割 description 字符串为数组。若 description 为 None(falsy),则 third_scenes 为空数组。page_size 最大值限制: scene_templates 和 recognition_records 接口均限制 page_size 不超过 100。