You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1207 lines
38 KiB

6 months ago
  1. ## 📌 软件框架概述
  2. 该架构是一个单机前后端BS架构,没有并发,而且也不可能并发,因为设备层没有那么多冗余资源。
  3. 软件采用前后端分离的架构,前端采用Vue,后端采用FastAPI,数据库选用向量数据库Postgresql。
  4. ## 📋 页面1:用户注册页面 (扫码)
  5. - **说明**: 此页面通过二维码引导用户进行自助注册,适用于现场排队等候的场景。管理员可在管理后台生成或展示此注册页面的二维码。
  6. - **跳转条件**:
  7. - 新用户注册成功后跳转到基本信息确认页面
  8. - **路由**: /api/v3/register
  9. - **访问方式**:POST
  10. - **注意事项**:
  11. - 新用户填写完毕后也需要跳信息确认,确认前不要弹给后端
  12. - 确认后等待后端返回,除非确认成功否则不跳转,提示用户修改对应字段
  13. - 后端在确认无误后会插入数据库的`patient_info`表单。
  14. - **请求参数**:
  15. ```json
  16. {
  17. "medical_record_number": "string", // 就诊号, 将作为登录用户名
  18. "id_last_six": "string", // 身份证后六位, 将作为登录密码
  19. "name": "string", // 姓名
  20. "gender": "string", // 性别
  21. "dominant_hand": "string", // 利手
  22. "diagnosis": "string", // 诊断
  23. "dob": "string", // 出生年月 (格式: YYYY-MM-DD)
  24. "height_cm": "number", // 身高(cm)
  25. "weight_kg": "number", // 体重(kg)
  26. "contact": "string", // 联系方式
  27. "inpatient_number": "string", // 住院号 (可选)
  28. "bed_number": "string", // 床号 (可选)
  29. "education_level": "string", // 教育程度 (可选)
  30. "education_years": "number", // 教育年数 (可选)
  31. "remarks": "string" // 备注 (可选)
  32. }
  33. ```
  34. - **响应格式**:
  35. ```json
  36. // 注册成功响应
  37. {
  38. "status": "success",
  39. "code": 200,
  40. "data": {
  41. "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  42. "token_type": "Bearer",
  43. "is_admin": false,
  44. "user_info": {
  45. "user_id": "user-abc-123",
  46. "medical_record_number": "J0012345",
  47. "name": "张三",
  48. "gender": "男",
  49. "dominant_hand": "右",
  50. "diagnosis": "无",
  51. "dob": "1960-01-15",
  52. "height_cm": 175,
  53. "weight_kg": 70,
  54. "contact": "13800138000",
  55. "inpatient_number": "Z67890",
  56. "bed_number": "503",
  57. "education_level": "本科",
  58. "education_years": 16,
  59. "remarks": ""
  60. }
  61. },
  62. "message": "注册成功并自动登录"
  63. }
  64. // 用户名已存在响应
  65. {
  66. "status": "error",
  67. "code": 400,
  68. "message": "Username Already Exists",
  69. "error_details": {
  70. "type": "duplicate_username",
  71. "description": "该用户名已被注册"
  72. }
  73. }
  74. // 邮箱已存在响应
  75. {
  76. "status": "error",
  77. "code": 400,
  78. "message": "Email Already Exists",
  79. "error_details": {
  80. "type": "duplicate_email",
  81. "description": "该邮箱已被注册"
  82. }
  83. }
  84. // 参数验证失败响应
  85. {
  86. "status": "error",
  87. "code": 400,
  88. "message": "Invalid Parameters",
  89. "error_details": {
  90. "type": "validation_error",
  91. "description": "参数验证失败",
  92. "fields": {
  93. "email": "邮箱格式不正确",
  94. "password": "密码长度必须大于6位"
  95. }
  96. }
  97. }
  98. ```
  99. ## 📋 页面2:登录页面
  100. - 功能要求:输入用户名密码,发后端验证
  101. - 跳转条件:登录成功后根据用户类型跳转
  102. - 管理员用户:跳转到数据库可视化页面
  103. - 普通用户:跳转到基本信息确认页面
  104. - 路由: /api/v3/login
  105. - 访问方式:POST
  106. - 请求参数:
  107. ```json
  108. {
  109. "username": "string", // 用户名
  110. "password": "string" // 密码
  111. }
  112. ```
  113. - 响应格式:
  114. ```json
  115. // 管理员用户响应
  116. {
  117. "status": "success",
  118. "code": 200,
  119. "data": {
  120. "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  121. "token_type": "Bearer",
  122. "is_admin": true,
  123. "active_log_table": "log_20240401_1"
  124. },
  125. "message": "管理员登录成功,已创建新的测试会话日志表"
  126. }
  127. // 普通用户响应
  128. {
  129. "status": "success",
  130. "code": 200,
  131. "data": {
  132. "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  133. "token_type": "Bearer",
  134. "is_admin": false,
  135. "user_info": {
  136. "user_id": "user-abc-123",
  137. "medical_record_number": "J0012345",
  138. "name": "张三",
  139. "gender": "男",
  140. "dominant_hand": "右",
  141. "diagnosis": "无",
  142. "dob": "1960-01-15",
  143. "height_cm": 175,
  144. "weight_kg": 70,
  145. "contact": "13800138000",
  146. "inpatient_number": "Z67890",
  147. "bed_number": "503",
  148. "education_level": "本科",
  149. "education_years": 16,
  150. "remarks": ""
  151. }
  152. },
  153. "message": "登录成功,令牌长期有效,用户信息已包含在令牌中"
  154. }
  155. // 错误响应
  156. {
  157. "status": "error",
  158. "code": 401,
  159. "message": "Unauthorized",
  160. "error_details": {
  161. "type": "invalid_credentials",
  162. "description": "Invalid username or password"
  163. }
  164. }
  165. ```
  166. ## 📋 页面3:基本信息确认页面
  167. # 功能1:基本信息确认
  168. - 跳转条件:
  169. - 普通用户登录或新用户注册成功后直接跳转至此页面
  170. - 确认信息后跳转到姿态识别页面
  171. - 路由: 无独立后端API。此页面为纯前端页面,用于展示登录时获取的`user_info`,用户确认后前端负责路由跳转。
  172. - 如果页面1验证为普通用户,跳转后让他直接确认
  173. ## 📋 页面4:姿态识别页面
  174. - 跳转条件:
  175. - 基本信息确认完成后跳转至此页面
  176. - 测试时间结束显示"功能测试1已结束,将在X秒后跳转下一页面"
  177. - 结束方式:时间到自动结束,计时由前端执行。
  178. # 功能1:开始姿态识别推流
  179. - 路由: /api/v3/streams
  180. - 访问:POST
  181. - 请求头:
  182. ```
  183. Authorization: Bearer {access_token} // 登录接口获取的token
  184. ```
  185. - 请求参数:无
  186. - 响应:
  187. ```json
  188. // 开始推流成功响应
  189. {
  190. "status": "success",
  191. "code": 200,
  192. "data": {
  193. "stream_id": "stream_123456", // 流ID,用于后续停止推流
  194. "ws_url": "ws://{host}/api/v3/ws/streams/{stream_id}?token={access_token}",
  195. "message": "推流服务已启动,请建立WebSocket连接"
  196. }
  197. }
  198. // 错误响应 - 摄像头未就绪
  199. {
  200. "status": "error",
  201. "code": 503,
  202. "message": "摄像头未就绪",
  203. "error_details": {
  204. "type": "camera_not_ready",
  205. "description": "请检查摄像头连接"
  206. }
  207. }
  208. // 错误响应 - 服务繁忙
  209. {
  210. "status": "error",
  211. "code": 503,
  212. "message": "服务繁忙",
  213. "error_details": {
  214. "type": "service_busy",
  215. "description": "当前服务负载过高,请稍后重试"
  216. }
  217. }
  218. // 错误响应 - 未授权
  219. {
  220. "status": "error",
  221. "code": 401,
  222. "message": "未授权访问",
  223. "error_details": {
  224. "type": "unauthorized",
  225. "description": "请先登录"
  226. }
  227. }
  228. ```
  229. # 功能2:停止姿态识别推流
  230. - 路由: /api/v3/streams/{stream_id}
  231. - 访问:DELETE
  232. - 请求头:
  233. ```
  234. Authorization: Bearer {access_token} // 登录接口获取的token
  235. ```
  236. - 响应:
  237. ```json
  238. // 停止推流成功响应
  239. {
  240. "status": "success",
  241. "code": 200,
  242. "data": {
  243. "message": "推流服务已停止"
  244. }
  245. }
  246. // 错误响应 - 无效的流ID
  247. {
  248. "status": "error",
  249. "code": 400,
  250. "message": "无效的流ID",
  251. "error_details": {
  252. "type": "invalid_stream_id",
  253. "description": "指定的流ID不存在或已过期"
  254. }
  255. }
  256. // 错误响应 - 未授权
  257. {
  258. "status": "error",
  259. "code": 401,
  260. "message": "未授权访问",
  261. "error_details": {
  262. "type": "unauthorized",
  263. "description": "请先登录"
  264. }
  265. }
  266. ```
  267. # 功能3:WebSocket通信
  268. - 连接地址:由`POST /api/v3/streams`响应中的`ws_url`提供
  269. - **说明**: 此WebSocket连接用于实现实时的医患交互引导。后端通过姿态识别算法实时分析视频流,判断用户当前所处的测试阶段,并将阶段标识 (`stage`) 推送给前端。
  270. - **工作流程**:
  271. 1. 后端实时分析视频流中的姿态数据,并维护一个测试流程的状态机。
  272. 2. 当检测到阶段变化时(如用户从"坐姿"变为"站立"),后端向前端推送新的阶段`stage`。
  273. 3. 前端接收到`stage`后,负责根据该标识查找并显示对应的提示文本,以及播放对应的语音提示。所有提示内容(文本、音频文件名)都预置在前端。
  274. - **服务端推送数据**:
  275. ```json
  276. {
  277. "video_frame": "base64_encoded_image",
  278. "timestamp": "2024-03-15T14:30:00Z",
  279. "stream_id": "stream_123456",
  280. "analysis_data": {
  281. "stage": "stand_up" // 当前阶段。可能的值: 'initial', 'stand_up', 'walk_to_target', 'turn', 'walk_back', 'sit_down', 'complete', 'error'
  282. }
  283. }
  284. ```
  285. ## 📋 页面5:视频交互页面
  286. - **说明**: 在这个页面,用户将观看一个预设的视频,并回答相关问题。
  287. - **跳转条件**:
  288. - 页面4结束后跳转。
  289. # 功能1:获取视频及问卷列表
  290. - **路由**: /api/v3/videos
  291. - **访问方式**: GET
  292. - **说明**: 一次性获取所有可用的视频及其关联的问卷。前端加载此页面时调用,简化后续API请求。
  293. - **请求头**:
  294. ```
  295. Authorization: Bearer {access_token}
  296. ```
  297. - **响应**:
  298. ```json
  299. // 成功响应
  300. {
  301. "status": "success",
  302. "code": 200,
  303. "data": {
  304. "videos": [
  305. {
  306. "video_id": "video_123456",
  307. "title": "场景一:公园散步",
  308. "description": "一段描述在公园里散步的视频。",
  309. "duration": 300,
  310. "questions": [
  311. { "id": "q1", "type": "text", "content": "请描述视频中展示的主要问题是什么?", "required": true, "max_length": 500 },
  312. { "id": "q2", "type": "text", "content": "您认为应该如何解决这个问题?", "required": true, "max_length": 1000 }
  313. ]
  314. },
  315. {
  316. "video_id": "video_789012",
  317. "title": "场景二:超市购物",
  318. "description": "一段模拟在超市购物场景的视频。",
  319. "duration": 240,
  320. "questions": [
  321. { "id": "q3", "type": "text", "content": "您对这个解决方案有什么建议?", "required": false, "max_length": 800 }
  322. ]
  323. }
  324. ]
  325. }
  326. }
  327. ```
  328. # 功能2:获取视频文件
  329. - **路由**: /api/v3/videos/{video_id}.mp4
  330. - **访问方式**:GET
  331. - **描述**: 此接口用于前端播放器实际获取视频文件流。为简化访问,视频ID本身已是不可猜测的,此接口可不要求JWT认证。
  332. - **响应**: 视频文件流 (MIME类型: `video/mp4`)
  333. # 功能3:多模态实时交互 (WebSocket)
  334. - **后端架构**: 为了确保数据采集的独立性和实时性,后端采用多进程架构。当会话启动时,会生成一个主控进程 (`session_manager.py`),该进程会进一步启动三个独立的子进程:
  335. - **`eye_data_collector.py`**: 专职采集眼动数据,并实时写入本地CSV文件,不受其他进程干扰。
  336. - **`face_data_collector.py`**: 专职采集面部表情数据,并实时写入本地CSV文件,不受其他进程干扰。
  337. - **`handwriting_server.py`**: 专职运行WebSocket服务器,用于处理与前端的手写交互。
  338. - **WebSocket URL**: 由 `POST /api/v3/video-sessions` 接口动态返回,格式类似于 `ws://127.0.0.1:{port}`。前端必须使用此接口返回的URL进行连接。
  339. - **说明**: 此架构确保了不同设备的数据采集(眼动、面部)可以真正并行,避免了因Python的GIL(全局解释器锁)或设备采样率不同导致的时序问题。
  340. - **工作流程与阶段**:
  341. 1. **会话启动与被动采集**: API (`POST /video-sessions`) 启动后端的 `session_manager.py`,后者立即启动 `eye_data_collector``face_data_collector` 进程,开始在后台静默采集数据。
  342. 2. **建立连接**: 前端使用API返回的`ws_url`与 `handwriting_server.py` 建立WebSocket连接。
  343. 3. **手写交互**: 前端可以随时向WebSocket发送手写数据(例如 `{"type": "handwriting_stroke", "payload": ...}`)。`handwriting_server` 负责接收。
  344. 4. **会话结束**: 前端发送会话结束指令 (例如: `{"command": "end_session"}`) 给WebSocket。
  345. 5. **服务关闭**: `handwriting_server` 收到结束指令后,通过进程间通信通知 `session_manager`。`session_manager` 随即安全地关闭所有相关的子进程(眼动、面部和WebSocket),完成数据保存和资源清理。
  346. - **数据格式**:
  347. - 通信主要由前端发起的指令和数据构成。
  348. - **前端 -> 后端 (WebSocket)**:
  349. - 指令: `{"command": "end_session"}`
  350. - 数据: `{"type": "handwriting_stroke", "payload": ...}`
  351. ## 📋 页面6:语音交互页面
  352. - **说明**: 采用异步处理模式。用户上传录音后,后端立即响应并开始处理。前端通过SSE(服务器发送事件)连接接收处理进度(语音识别 -> AI对话 -> 语音合成),并实时更新UI,为用户提供流畅的交互反馈。
  353. - **跳转条件**:
  354. - 页面8提交问卷后,或页面8按下手动结束跳转(这里需要提示内容为空,是否强制跳转)
  355. - **工作流程**:
  356. 1. **创建会话**: 前端通过 `POST /api/v3/audio-sessions` 创建新会话。
  357. 2. **上传音频**: 用户完成录音后,前端调用 `POST /api/v3/audio-sessions/{session_id}/interact` 上传音频。
  358. 3. **启动处理**: 后端立即返回一个 `request_id` 和一个SSE连接地址,并开始在后台异步处理音频。
  359. 4. **监听事件**: 前端使用返回的地址建立SSE连接,开始监听来自服务器的进度事件。
  360. 5. **阶段一:语音识别 (ASR)**: 后端完成ASR后,通过SSE推送 `asr_result` 事件。前端接收到后,在界面上显示识别出的用户文本。
  361. 6. **阶段二:AI对话**: 后端将ASR文本送入AI模型,完成后通过SSE推送 `ai_result` 事件。前端接收后,显示AI的文本回复。
  362. 7. **阶段三:语音合成 (TTS)**: 后端将AI文本进行TTS,完成后通过SSE推送 `tts_result` 事件,包含音频文件的URL。
  363. 8. **播放与结束**: 前端接收到音频URL后,播放AI的语音回复。最后,服务器推送 `done` 事件,关闭SSE连接。
  364. # 功能1:开始语音交互会话
  365. - **路由**: /api/v3/audio-sessions
  366. - **访问方式**:POST
  367. - **请求头**:
  368. ```
  369. Authorization: Bearer {access_token}
  370. ```
  371. - **请求参数 (可选)**:
  372. ```json
  373. {
  374. "system_prompt": "你是一个聊天机器人,请根据用户需求进行回应。",
  375. "max_history": 10
  376. }
  377. ```
  378. - **响应**:
  379. ```json
  380. // 开始会话成功响应
  381. {
  382. "status": "success",
  383. "code": 200,
  384. "data": {
  385. "session_id": "session_123456",
  386. "message": "语音交互会话已启动"
  387. }
  388. }
  389. ```
  390. # 功能2:发起异步语音对话
  391. - **路由**: /api/v3/audio-sessions/{session_id}/interact
  392. - **访问方式**:POST
  393. - **说明**: 这是一个异步接口。它会立即返回,并启动一个后台任务来处理音频。处理进度通过SSE推送。
  394. - **请求头**:
  395. ```
  396. Authorization: Bearer {access_token}
  397. Content-Type: multipart/form-data
  398. ```
  399. - **请求体**:
  400. - `audio`: 用户录制的音频文件 (例如 `blob``.wav` 格式)
  401. - **响应 (HTTP 202 Accepted)**:
  402. ```json
  403. // 成功接收请求
  404. {
  405. "status": "accepted",
  406. "code": 202,
  407. "data": {
  408. "request_id": "req_abc123",
  409. "events_url": "/api/v3/audio-sessions/{session_id}/events/{request_id}",
  410. "message": "请求已接收,请连接到events_url获取实时进度"
  411. }
  412. }
  413. ```
  414. # 功能3:监听处理事件 (SSE)
  415. - **路由**: /api/v3/audio-sessions/{session_id}/events/{request_id}
  416. - **协议**: `text/event-stream`
  417. - **说明**: 前端与此端点建立连接以接收实时事件。
  418. - **服务端推送事件格式**:
  419. - **ASR完成**:
  420. ```
  421. event: asr_result
  422. data: {"status": "success", "text": "用户说的话", "confidence": 0.95}
  423. ```
  424. - **AI回复完成**:
  425. ```
  426. event: ai_result
  427. data: {"status": "success", "text": "AI的回复文本"}
  428. ```
  429. - **TTS完成**:
  430. ```
  431. event: tts_result
  432. data: {"status": "success", "audio_url": "/api/v3/audios/audio_xyz.wav"}
  433. ```
  434. - **任务结束**:
  435. ```
  436. event: done
  437. data: {"status": "success", "message": "处理完成"}
  438. ```
  439. - **发生错误**:
  440. ```
  441. event: error
  442. data: {"status": "error", "stage": "asr", "message": "ASR处理失败"}
  443. ```
  444. # 功能4:获取对话历史
  445. - **路由**: /api/v3/audio-sessions/{session_id}/history
  446. - **访问方式**: GET
  447. - **请求头**:
  448. ```
  449. Authorization: Bearer {access_token}
  450. ```
  451. - **响应**:
  452. ```json
  453. // 成功响应
  454. {
  455. "status": "success",
  456. "code": 200,
  457. "data": {
  458. "conversation_history": [
  459. { "role": "user", "content": "你好" },
  460. { "role": "assistant", "content": "你好,有什么可以帮你的吗?" }
  461. ]
  462. }
  463. }
  464. ```
  465. # 功能5:结束语音交互会话
  466. - **路由**: /api/v3/audio-sessions/{session_id}
  467. - **访问方式**:DELETE
  468. - **请求头**:
  469. ```
  470. Authorization: Bearer {access_token}
  471. ```
  472. - **响应**:
  473. ```json
  474. // 结束会话成功响应
  475. {
  476. "status": "success",
  477. "code": 200,
  478. "data": { "message": "语音交互会话已结束" }
  479. }
  480. ```
  481. # 功能6:获取音频文件
  482. - **路由**: /api/v3/audios/{audio_id}.wav
  483. - **访问方式**:GET
  484. - **描述**: 此接口用于前端播放器实际获取TTS生成的音频文件。
  485. - **响应**: 音频文件内容 (e.g., `audio/wav`)
  486. ## 📋 页面7:历史测试记录查询页面
  487. # 功能1:获取用户的历史测试记录表
  488. - 跳转条件:仅管理员用户可访问。登录成功后,管理员将直接跳转到此页面。普通用户无权访问。
  489. - 路由: /api/v3/admin/logs
  490. - 方法: GET
  491. - 认证: `Authorization: Bearer {access_token}`
  492. - 返回:
  493. ```json
  494. // 成功响应
  495. {
  496. "status": "success",
  497. "code": 200,
  498. "data": {
  499. "tables": [
  500. {
  501. "table_name": "test_20240315_1",
  502. "created_at": "2024-03-15T14:30:00Z",
  503. "description": "2024年3月15日第一次测试"
  504. },
  505. {
  506. "table_name": "test_20240315_2",
  507. "created_at": "2024-03-15T16:30:00Z",
  508. "description": "2024年3月15日第二次测试"
  509. }
  510. ]
  511. }
  512. }
  513. // 无数据响应
  514. {
  515. "status": "success",
  516. "code": 200,
  517. "data": {
  518. "tables": []
  519. }
  520. }
  521. // 失败响应
  522. {
  523. "status": "error",
  524. "code": 403,
  525. "message": "Forbidden",
  526. "error_details": {
  527. "type": "permission_denied",
  528. "description": "You don't have permission to access test records"
  529. }
  530. }
  531. ```
  532. ## 📋 页面8:单次测试记录列表页面
  533. # 功能1:查询单次测试的所有记录
  534. - **说明**: 从历史测试记录页面选择一个批次后,跳转到此页面,展示该批次下的所有测试者记录。
  535. - **路由**: /api/v3/admin/logs/{table_name}
  536. - **方法**: GET
  537. - **认证**: `Authorization: Bearer {access_token}`
  538. - **请求参数 (Query Parameters)**:
  539. - `page` (number, optional, default: 1): 页码,从1开始
  540. - `page_size` (number, optional, default: 50): 每页记录数
  541. - **示例**: `/api/v3/admin/logs/log_20240315_1?page=1&page_size=50`
  542. - **返回**:
  543. ```json
  544. // 成功响应
  545. {
  546. "status": "success",
  547. "code": 200,
  548. "data": {
  549. "total": 100, // 总记录数
  550. "total_pages": 2, // 总页数
  551. "current_page": 1, // 当前页码
  552. "page_size": 50, // 每页记录数
  553. "records": [ // 当前页的记录
  554. {
  555. "log_id": 1,
  556. "medical_record_number": "J0012345",
  557. "name": "张三",
  558. "created_at": "2024-03-15T08:30:00Z",
  559. "status": "completed"
  560. },
  561. {
  562. "log_id": 2,
  563. "medical_record_number": "J0012346",
  564. "name": "李四",
  565. "created_at": "2024-03-15T08:31:00Z",
  566. "status": "pending_review"
  567. },
  568. {
  569. "log_id": 3,
  570. "medical_record_number": "J0012347",
  571. "name": "王五",
  572. "created_at": "2024-03-15T08:32:00Z",
  573. "status": "initialized"
  574. }
  575. ]
  576. }
  577. }
  578. - **`status` 字段说明**:
  579. - `initialized`: 已初始化。记录已创建,等待用户录入数据。
  580. - `processing`: 数据处理中。用户已完成记录,系统正在后台分析数据。
  581. - `pending_review`: 待专家审核。系统分析完成,等待专家进行评级和确认。
  582. - `completed`: 已完成。专家已完成确认,记录归档。
  583. // 查询失败响应
  584. {
  585. "status": "error",
  586. "code": 404,
  587. "message": "Not Found",
  588. "error_details": {
  589. "type": "invalid_table",
  590. "description": "Log table does not exist"
  591. }
  592. }
  593. // 权限失败响应
  594. {
  595. "status": "error",
  596. "code": 403,
  597. "message": "Access Denied",
  598. "error_details": {
  599. "type": "permission_denied",
  600. "description": "You don't have permission to access this test record"
  601. }
  602. }
  603. ```
  604. ## 📋 页面9:分析模块详情与编辑
  605. 本部分包含所有针对单个测试记录的具体分析模块。用户从记录列表页选择具体项目后,前端访问对应的页面URL进入编辑与查看。
  606. ### 4.1 步态分析页面
  607. # 功能1:获取步态分析数据
  608. - **路由**: `GET /api/v3/admin/logs/{table_name}/{log_id}/gait`
  609. - **认证**: `Authorization: Bearer {access_token}`
  610. - **说明**: 进入步态分析页面时调用,获取该记录中所有行走分段的步态分析结果。一次记录可能包含多次行走,每次行走都是一个独立的分析单元。
  611. - **响应**:
  612. ```json
  613. {
  614. "status": "success",
  615. "code": 200,
  616. "data": {
  617. "procedural_events": [
  618. { "event": "stand_up", "frame": 85 },
  619. { "event": "turn_around", "frame": 755 },
  620. { "event": "sit_down", "frame": 1560 }
  621. ],
  622. "walk_segments": [
  623. {
  624. "segment_id": 1,
  625. "start_frame": 153,
  626. "end_frame": 750,
  627. "calculated_metrics": {
  628. "gait_speed": 1.2,
  629. "stride_length": 0.75,
  630. "step_speed": 1.1,
  631. "swing_speed": 2.5,
  632. "cadence": 110.0,
  633. "single_support_phase_ratio": 0.4,
  634. "swing_phase_ratio": 0.4,
  635. "double_support_ratio": 0.2,
  636. "step_height": 0.15,
  637. "step_width": 0.2
  638. },
  639. "events": [
  640. { "event": "left_heel_strike", "frame": 165 },
  641. { "event": "right_toe_off", "frame": 168 },
  642. { "event": "double_support", "frame": 170 },
  643. { "event": "right_heel_strike", "frame": 180 },
  644. { "event": "left_toe_off", "frame": 183 },
  645. ]
  646. },
  647. ...
  648. ]
  649. }
  650. }
  651. ```
  652. # 功能2:编辑事件并重新计算步态参数
  653. - **路由**: `POST /api/v3/admin/logs/{table_name}/{log_id}/gait/events`
  654. - **认证**: `Authorization: Bearer {access_token}`
  655. - **说明**: 此功能用于提交修正后的所有关键事件标记(包括`stand_up`, `turn_around`, `sit_down`等过程性事件,以及定义行走分段的`walk_start`, `walk_end`事件)。后端接收到新的事件列表后,将立即执行重新计算,并返回更新后的完整步态分析数据。
  656. - **请求体**:
  657. ```json
  658. {
  659. "events": [
  660. { "event": "stand_up", "frame": 85 },
  661. { "event": "walk_start", "frame": 180 },
  662. { "event": "walk_end", "frame": 840 },
  663. { "event": "turn_around", "frame": 900 },
  664. { "event": "sit_down", "frame": 1600 }
  665. ]
  666. }
  667. ```
  668. - **响应**:
  669. ```json
  670. - 成功响应:返回更新后的完整步态分析数据,结构同`功能1:获取步态分析数据`的响应。
  671. - 请求无效响应
  672. {
  673. "status": "error",
  674. "code": 400,
  675. "message": "Bad Request",
  676. "error_details": {
  677. "type": "invalid_event_format",
  678. "description": "The submitted event data is incorrectly formatted or frames are invalid."
  679. }
  680. }
  681. - 未授权响应
  682. {
  683. "status": "error",
  684. "code": 403,
  685. "message": "Forbidden",
  686. "error_details": {
  687. "type": "permission_denied",
  688. "description": "You do not have permission to modify this resource."
  689. }
  690. }
  691. ```
  692. # 功能3:下载原始时序数据 (CSV)
  693. - **路由**: `GET /api/v3/admin/logs/{table_name}/{log_id}/raw`
  694. - **认证**: `Authorization: Bearer {access_token}`
  695. - **说明**: 为支持后续的研究和算法改进,系统需保留原始的时序数据。此接口提供对指定记录的原始数据(包含COCO骨骼节点时序信息的CSV文件)的下载功能。
  696. - **响应**:
  697. - 后端直接返回文件流。
  698. - **响应头 (Headers)**:
  699. - **Content-Type**: `text/csv`
  700. - **Content-Disposition**: `attachment; filename="raw_data_{log_id}.csv"`
  701. ### 4.2 面部表情分析页面 (UPDRS评级)
  702. 此部分提供对视频中的整体面部表情进行UPDRS评级的功能。评级是针对整个视频的单个分数。
  703. - **UPDRS面部表情评级标准**:
  704. - **0**: 正常
  705. - **1**: 极轻微的表情异常
  706. - **2**: 轻度而肯定的表情呆板
  707. - **3**: 中度的面部表情损害,仍能张口
  708. - **4**: 呈面具脸,面部表情严重或完全消失
  709. # 功能1:获取面部表情视频及当前评级
  710. - **路由**: `GET /api/v3/admin/logs/{table_name}/{log_id}/facial`
  711. - **认证**: `Authorization: Bearer {access_token}`
  712. - **说明**: 获取用于评级的面部表情视频,以及该记录当前已有的UPDRS分数。
  713. - **响应**:
  714. ```json
  715. // 成功响应
  716. {
  717. "status": "success",
  718. "code": 200,
  719. "data": {
  720. "log_id": 1,
  721. "video_url": "/api/v3/videos/facial_expression_video_abc.mp4",
  722. "updrs_rating": 1 // 当前UPDRS分数,如果未评级则为null
  723. }
  724. }
  725. // 记录不存在响应
  726. {
  727. "status": "error",
  728. "code": 404,
  729. "message": "Not Found",
  730. "error_details": {
  731. "type": "record_not_found",
  732. "description": "The specified record does not exist."
  733. }
  734. }
  735. // 未授权响应
  736. {
  737. "status": "error",
  738. "code": 403,
  739. "message": "Forbidden",
  740. "error_details": {
  741. "type": "permission_denied",
  742. "description": "You do not have permission to access this resource."
  743. }
  744. }
  745. ```
  746. # 功能2:提交/更新UPDRS评级
  747. - **路由**: `POST /api/v3/admin/logs/{table_name}/{log_id}/facial/rating`
  748. - **认证**: `Authorization: Bearer {access_token}`
  749. - **说明**: 为整个视频提交一个UPDRS评级分数(0-4)。
  750. - **请求体**:
  751. ```json
  752. {
  753. "rating": 2
  754. }
  755. ```
  756. - **响应**:
  757. ```json
  758. // 成功响应
  759. {
  760. "status": "success",
  761. "code": 200,
  762. "data": {
  763. "message": "UPDRS rating updated successfully."
  764. }
  765. }
  766. // 请求无效响应
  767. {
  768. "status": "error",
  769. "code": 400,
  770. "message": "Bad Request",
  771. "error_details": {
  772. "type": "invalid_rating_value",
  773. "description": "Rating must be an integer between 0 and 4."
  774. }
  775. }
  776. // 未授权响应
  777. {
  778. "status": "error",
  779. "code": 403,
  780. "message": "Forbidden",
  781. "error_details": {
  782. "type": "permission_denied",
  783. "description": "You do not have permission to modify this resource."
  784. }
  785. }
  786. ```
  787. ### 4.3 眼动分析页面 (UPDRS评级)
  788. 此部分提供对眼动追踪视频进行评级的功能。评级主要关注扫视和凝视的稳定性。
  789. - **眼动功能评级标准 (参考UPDRS)**:
  790. - **0**: 正常,眼跳和凝视稳定、准确。
  791. - **1**: 轻微异常,扫视速度轻度减慢或偶有不准确。
  792. - **2**: 轻度异常,扫视速度变慢,凝视不稳定。
  793. - **3**: 中度异常,扫视启动困难,有明显的凝视不稳或眼球震颤。
  794. - **4**: 严重异常,无法完成扫视任务或持续的凝视不稳。
  795. # 功能1:获取眼动分析数据及当前评级
  796. - **路由**: `GET /api/v3/admin/logs/{table_name}/{log_id}/eyetracking`
  797. - **认证**: `Authorization: Bearer {access_token}`
  798. - **说明**: 获取指定记录的眼动追踪视频和当前已有的评级分数。
  799. - **响应**:
  800. ```json
  801. // 成功响应
  802. {
  803. "status": "success",
  804. "code": 200,
  805. "data": {
  806. "video_url": "/api/v3/videos/eyetracking_video_abc.mp4",
  807. "rating": 2 // 当前评级分数,如果未评级则为null
  808. }
  809. }
  810. // 记录不存在响应
  811. {
  812. "status": "error",
  813. "code": 404,
  814. "message": "Not Found",
  815. "error_details": {
  816. "type": "record_not_found",
  817. "description": "The specified record does not exist."
  818. }
  819. }
  820. // 未授权响应
  821. {
  822. "status": "error",
  823. "code": 403,
  824. "message": "Forbidden",
  825. "error_details": {
  826. "type": "permission_denied",
  827. "description": "You do not have permission to access this resource."
  828. }
  829. }
  830. ```
  831. # 功能2:提交/更新眼动功能评级
  832. - **路由**: `POST /api/v3/admin/logs/{table_name}/{log_id}/eyetracking/rating`
  833. - **认证**: `Authorization: Bearer {access_token}`
  834. - **说明**: 提交对眼动功能的评级分数(0-4)。
  835. - **请求体**:
  836. ```json
  837. {
  838. "rating": 3
  839. }
  840. ```
  841. - **响应**:
  842. ```json
  843. // 成功响应
  844. {
  845. "status": "success",
  846. "code": 200,
  847. "data": {
  848. "message": "Eyetracking rating updated successfully."
  849. }
  850. }
  851. // 请求无效响应
  852. {
  853. "status": "error",
  854. "code": 400,
  855. "message": "Bad Request",
  856. "error_details": {
  857. "type": "invalid_rating_value",
  858. "description": "Rating must be an integer between 0 and 4."
  859. }
  860. }
  861. // 未授权响应
  862. {
  863. "status": "error",
  864. "code": 403,
  865. "message": "Forbidden",
  866. "error_details": {
  867. "type": "permission_denied",
  868. "description": "You do not have permission to modify this resource."
  869. }
  870. }
  871. ```
  872. ### 4.4 手写笔迹分析页面 (UPDRS评级)
  873. 此部分提供对手写笔迹(如螺旋测试)的评级功能,主要评估运动震颤和书写过小症(Micrographia)。
  874. - **手写功能评级标准 (参考UPDRS)**:
  875. - **0**: 正常,线条流畅,无明显震颤,大小正常。
  876. - **1**: 轻微异常,线条有极轻微的震颤或轻微的书写变小。
  877. - **2**: 轻度异常,线条有肯定的震颤,书写大小一致性变差,但仍清晰可辨。
  878. - **3**: 中度异常,震颤明显,书写过小症显著,辨认有一定困难。
  879. - **4**: 严重异常,震颤严重导致无法完成绘制,或字迹小到无法辨认。
  880. # 功能1:获取手写数据及当前评级
  881. - **路由**: `GET /api/v3/admin/logs/{table_name}/{log_id}/handwriting`
  882. - **认证**: `Authorization: Bearer {access_token}`
  883. - **说明**: 获取用于分析的手写笔迹视频和当前已有的评级分数。
  884. - **响应**:
  885. ```json
  886. // 成功响应
  887. {
  888. "status": "success",
  889. "code": 200,
  890. "data": {
  891. "video_url": "/api/v3/videos/handwriting_spiral_abc.mp4",
  892. "rating": 1 // 当前评级分数,如果未评级则为null
  893. }
  894. }
  895. // 记录不存在响应
  896. {
  897. "status": "error",
  898. "code": 404,
  899. "message": "Not Found",
  900. "error_details": {
  901. "type": "record_not_found",
  902. "description": "The specified record does not exist."
  903. }
  904. }
  905. // 未授权响应
  906. {
  907. "status": "error",
  908. "code": 403,
  909. "message": "Forbidden",
  910. "error_details": {
  911. "type": "permission_denied",
  912. "description": "You do not have permission to access this resource."
  913. }
  914. }
  915. ```
  916. # 功能2:提交/更新手写功能评级
  917. - **路由**: `POST /api/v3/admin/logs/{table_name}/{log_id}/handwriting/rating`
  918. - **认证**: `Authorization: Bearer {access_token}`
  919. - **说明**: 提交对手写功能的评级分数(0-4)。
  920. - **请求体**:
  921. ```json
  922. {
  923. "rating": 2
  924. }
  925. ```
  926. - **响应**:
  927. ```json
  928. // 成功响应
  929. {
  930. "status": "success",
  931. "code": 200,
  932. "data": {
  933. "message": "Handwriting rating updated successfully."
  934. }
  935. }
  936. // 请求无效响应
  937. {
  938. "status": "error",
  939. "code": 400,
  940. "message": "Bad Request",
  941. "error_details": {
  942. "type": "invalid_rating_value",
  943. "description": "Rating must be an integer between 0 and 4."
  944. }
  945. }
  946. // 未授权响应
  947. {
  948. "status": "error",
  949. "code": 403,
  950. "message": "Forbidden",
  951. "error_details": {
  952. "type": "permission_denied",
  953. "description": "You do not have permission to modify this resource."
  954. }
  955. }
  956. ```
  957. ### 4.5 语音分析页面 (UPDRS评级)
  958. 此部分提供对语音样本的评级,主要评估音量、音调、清晰度等言语功能。
  959. - **言语功能评级标准 (参考UPDRS)**:
  960. - **0**: 正常,语言清晰,音量正常。
  961. - **1**: 轻微异常,音量轻度减弱或发音偶有含糊。
  962. - **2**: 轻度异常,语言单调、含糊,但尚能听懂。
  963. - **3**: 中度异常,语言严重含糊,听懂有较大困难。
  964. - **4**: 严重异常,语言基本无法听懂或失语。
  965. # 功能1:获取语音及当前评级
  966. - **路由**: `GET /api/v3/admin/logs/{table_name}/{log_id}/speech`
  967. - **认证**: `Authorization: Bearer {access_token}`
  968. - **说明**: 获取用于分析的语音文件和当前已有的评级分数。
  969. - **响应**:
  970. ```json
  971. // 成功响应
  972. {
  973. "status": "success",
  974. "code": 200,
  975. "data": {
  976. "audio_url": "/api/v3/audios/speech_sample_abc.wav",
  977. "rating": 3 // 当前评级分数,如果未评级则为null
  978. }
  979. }
  980. // 记录不存在响应
  981. {
  982. "status": "error",
  983. "code": 404,
  984. "message": "Not Found",
  985. "error_details": {
  986. "type": "record_not_found",
  987. "description": "The specified record does not exist."
  988. }
  989. }
  990. // 未授权响应
  991. {
  992. "status": "error",
  993. "code": 403,
  994. "message": "Forbidden",
  995. "error_details": {
  996. "type": "permission_denied",
  997. "description": "You do not have permission to access this resource."
  998. }
  999. }
  1000. ```
  1001. # 功能2:提交/更新言语功能评级
  1002. - **路由**: `POST /api/v3/admin/logs/{table_name}/{log_id}/speech/rating`
  1003. - **认证**: `Authorization: Bearer {access_token}`
  1004. - **说明**: 提交对言语功能的评级分数(0-4)。
  1005. - **请求体**:
  1006. ```json
  1007. {
  1008. "rating": 3
  1009. }
  1010. ```
  1011. - **响应**:
  1012. ```json
  1013. // 成功响应
  1014. {
  1015. "status": "success",
  1016. "code": 200,
  1017. "data": {
  1018. "message": "Speech rating updated successfully."
  1019. }
  1020. }
  1021. // 请求无效响应
  1022. {
  1023. "status": "error",
  1024. "code": 400,
  1025. "message": "Bad Request",
  1026. "error_details": {
  1027. "type": "invalid_rating_value",
  1028. "description": "Rating must be an integer between 0 and 4."
  1029. }
  1030. }
  1031. // 未授权响应
  1032. {
  1033. "status": "error",
  1034. "code": 403,
  1035. "message": "Forbidden",
  1036. "error_details": {
  1037. "type": "permission_denied",
  1038. "description": "You do not have permission to modify this resource."
  1039. }
  1040. }
  1041. ```
  1042. ### 4.6 语义分析页面 (认知评级)
  1043. 此部分提供对文本(例如,语音识别结果)的评级,主要评估思维连贯性、逻辑性和复杂性。
  1044. - **认知与语义连贯性评级标准 (自定义)**:
  1045. - **0**: 正常,思维清晰,表达连贯,逻辑性强。
  1046. - **1**: 轻微异常,偶有思维中断或逻辑不连贯之处。
  1047. - **2**: 轻度异常,思维迟缓,表达重复,逻辑性差。
  1048. - **3**: 中度异常,思维混乱,难以组织语言,表达缺乏逻辑。
  1049. - **4**: 严重异常,无法形成有意义的句子或表达与问题完全无关。
  1050. # 功能1:获取文本及当前评级
  1051. - **路由**: `GET /api/v3/admin/logs/{table_name}/{log_id}/semantics`
  1052. - **认证**: `Authorization: Bearer {access_token}`
  1053. - **说明**: 获取指定记录的文本内容和当前已有的认知评级分数。
  1054. - **响应**:
  1055. ```json
  1056. // 成功响应
  1057. {
  1058. "status": "success",
  1059. "code": 200,
  1060. "data": {
  1061. "text_content": "今天天气真好,我感觉心情非常愉快,虽然昨天有点不舒服,但现在好多了。",
  1062. "rating": 0 // 当前评级分数,如果未评级则为null
  1063. }
  1064. }
  1065. // 记录不存在响应
  1066. {
  1067. "status": "error",
  1068. "code": 404,
  1069. "message": "Not Found",
  1070. "error_details": {
  1071. "type": "record_not_found",
  1072. "description": "The specified record does not exist."
  1073. }
  1074. }
  1075. // 未授权响应
  1076. {
  1077. "status": "error",
  1078. "code": 403,
  1079. "message": "Forbidden",
  1080. "error_details": {
  1081. "type": "permission_denied",
  1082. "description": "You do not have permission to access this resource."
  1083. }
  1084. }
  1085. ```
  1086. # 功能2:提交/更新认知评级
  1087. - **路由**: `POST /api/v3/admin/logs/{table_name}/{log_id}/semantics/rating`
  1088. - **认证**: `Authorization: Bearer {access_token}`
  1089. - **说明**: 提交对认知与语义连贯性的评级分数(0-4)。
  1090. - **请求体**:
  1091. ```json
  1092. {
  1093. "rating": 1
  1094. }
  1095. ```
  1096. - **响应**:
  1097. ```json
  1098. // 成功响应
  1099. {
  1100. "status": "success",
  1101. "code": 200,
  1102. "data": {
  1103. "message": "Semantic rating updated successfully."
  1104. }
  1105. }
  1106. // 请求无效响应
  1107. {
  1108. "status": "error",
  1109. "code": 400,
  1110. "message": "Bad Request",
  1111. "error_details": {
  1112. "type": "invalid_rating_value",
  1113. "description": "Rating must be an integer between 0 and 4."
  1114. }
  1115. }
  1116. // 未授权响应
  1117. {
  1118. "status": "error",
  1119. "code": 403,
  1120. "message": "Forbidden",
  1121. "error_details": {
  1122. "type": "permission_denied",
  1123. "description": "You do not have permission to modify this resource."
  1124. }
  1125. }
  1126. ```