feat: demo CORS, demo client, openpyxl catalog load
- Load consumable catalog XLSX with openpyxl and drop the pandas dependency. - Add optional demo CORS settings and FastAPI CORSMiddleware for browser clients. - Add scripts/demo_client static page and local server for API smoke tests. Made-with: Cursor
This commit is contained in:
64
scripts/demo_client/README.md
Normal file
64
scripts/demo_client/README.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# Demo Client
|
||||
|
||||
一个浏览器里的单页 demo,用于手动触发 `app/api.py` 里的 5 个 `/client/*` 接口,覆盖开始/结束手术、查询结果、拉取待确认耗材,以及**本地麦克风录 WAV 并上传**语音确认接口。
|
||||
|
||||
## 结构
|
||||
|
||||
```
|
||||
scripts/demo_client/
|
||||
server.py # 基于 stdlib 的静态服务器;额外暴露 /labels.json
|
||||
index.html # 单文件页面(原生 JS,零构建依赖)
|
||||
```
|
||||
|
||||
## 运行方式
|
||||
|
||||
```bash
|
||||
# 1) 启动后端(默认 38080)。CORS 中间件在 settings.demo_cors_enabled=True 时自动挂载。
|
||||
uv run python main.py
|
||||
|
||||
# 2) 启动 demo 客户端静态服务(默认 127.0.0.1:38081)。
|
||||
python scripts/demo_client/server.py
|
||||
# 或指定端口:
|
||||
python scripts/demo_client/server.py -p 9000 --host 0.0.0.0
|
||||
|
||||
# 3) 浏览器访问:
|
||||
open http://localhost:38081/
|
||||
```
|
||||
|
||||
页面顶部的「服务端 Base URL」默认是 `http://localhost:38080`;如果后端部署在其他主机/端口,直接改这里即可。
|
||||
|
||||
## 页面包含什么
|
||||
|
||||
- `GET /health` 连通性检查
|
||||
- §4.1 `POST /client/surgeries/start` — 含 `surgery_id` 校验、`camera_ids` 多值输入、`candidate_consumables` 标签编辑器(初始值从 `/labels.json` 载入,可增删)
|
||||
- §4.2 `POST /client/surgeries/end`
|
||||
- §4.3 `GET /client/surgeries/{id}/result` — 以表格渲染 `details` 与 `summary`
|
||||
- §4.4 `GET /client/surgeries/{id}/pending-confirmation` — 支持手动拉取与 2s 自动轮询
|
||||
- §4.5 `POST .../resolve` — 本地麦克风录音 → 16 kHz 单声道 WAV → `multipart/form-data` 上传
|
||||
|
||||
右侧「响应日志」按时间倒序展示每次请求的 method/url/status/body,便于联调截图。
|
||||
|
||||
## 关于 `/labels.json`
|
||||
|
||||
`server.py` 在进程启动时读 `app/resources/consumable_classifier_labels.yaml` 的 `names` 映射并返回 `{"labels": [...]}`。优先用 `PyYAML`(主项目依赖已间接引入),缺失时回退到手写的最小 YAML 解析器(仅兼容该文件的已知形状)。
|
||||
|
||||
## 关于麦克风
|
||||
|
||||
浏览器的 `getUserMedia` 仅在**安全上下文**可用,对 demo 实际意味着:
|
||||
|
||||
- **可以用**:`http://localhost`、`http://127.0.0.1`、`https://...`
|
||||
- **不能用**:直接 `file://` 双击打开 `index.html`,或通过非本机 `http://` 访问 —— 所以这里用了独立的静态 HTTP 服务器而不是 `file://`。
|
||||
|
||||
页面采用:
|
||||
|
||||
1. `navigator.mediaDevices.getUserMedia` 拿到单声道音轨
|
||||
2. `AudioContext` + `ScriptProcessorNode` 捕获 Float32 原始 PCM(输入采样率取决于系统,如 48 kHz)
|
||||
3. 前端把样本线性降采样到 16 kHz、转 Int16 并拼 RIFF/WAVE 头
|
||||
4. 产出 `Blob("audio/wav")` 后可以「下载 wav(调试)」或直接「上传并确认」
|
||||
|
||||
## 关闭 CORS(生产环境)
|
||||
|
||||
`app/config.py` 新增:
|
||||
|
||||
- `DEMO_CORS_ENABLED`(默认 `True`,生产请在 `.env` 里置 `false`)
|
||||
- `DEMO_CORS_ORIGINS`(默认 `*`,可写 `http://my-host:38081,https://or-demo.example.com`)
|
||||
Reference in New Issue
Block a user