ECG 长程快速分析 API
长程快速分析与长程分析并行提供,文件上传方式与请求参数完全一致,区别在于分析在秒级完成,并返回明确的任务状态。
快速分析采用异步模式,提交任务后通过轮询查询接口获取结果。
与长程分析的区别
两条通道并存,可按需选择。
| 长程分析 | 长程快速分析 | |
|---|---|---|
| 获取上传地址 | /api/v1/advanced/ecg/holter/upload-url | 同左 |
| 提交接口 | /api/v1/advanced/ecg/holter/submit | /api/v1/advanced/ecg/holter/fast/submit |
| 查询接口 | /api/v1/advanced/ecg/holter/result/:id | /api/v1/advanced/ecg/holter/fast/result/:taskId |
| 提交请求体 | fileUrl + 采集参数 | 同左 |
| 查询返回 | data 为 null 表示尚未完成 | data.status 显式给出任务状态 |
| 结果字段 | data.report 是 JSON 字符串,需二次解析 | data.result 已是 JSON 对象 |
| 结果内容 | 心率、HRV、QTc、节律、早搏、PDF 报告 | 心率、节律、早搏 |
| 记录时长上限 | 无 | 24 小时 |
快速分析结果不包含 HRV(hrvPer1Hours)、QT 间期校正(qtc)、有效信号时长(totalValidDuration)与 PDF 报告(pdfUrl)。如业务依赖这些字段,请使用长程分析。
分析流程
接口列表
| 接口 | 方法 | 说明 |
|---|---|---|
/api/v1/advanced/ecg/holter/upload-url | GET | 获取文件上传地址(与长程分析共用) |
/api/v1/advanced/ecg/holter/fast/submit | POST | 提交一条快速分析任务 |
/api/v1/advanced/ecg/holter/fast/result/:taskId | GET | 查询快速分析任务状态与结果 |
Step 1:获取上传地址
GET /api/v1/advanced/ecg/holter/upload-url
用于获取心电二进制文件的上传地址。该接口与长程分析通道相同,已接入长程分析的调用方无需改动这一步。
请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
fileType | string | 是 | 文件类型,当前仅支持 BINARY16、BIN3_16 |
请求示例
curl -X GET "https://api.heartvoice.com.cn/api/v1/advanced/ecg/holter/upload-url?fileType=BINARY16" \
-H "Authorization: Bearer YOUR_API_KEY"
响应示例
{
"errorCode": "0",
"msg": "成功",
"data": "https://ecgdata-1255716792.cos.ap-shanghai.myqcloud.com/openapi/2039546102478438400/2604021132295727.BINARY16?sign=xxx"
}
说明
- 返回值
data为文件上传地址。 - 客户端拿到地址后,自行完成文件上传。
- 上传地址有有效期,请在获取后尽快上传并提交分析。
- 上传文件格式说明如下。
文件上传示例
客户端获取到上传地址后,可直接使用该地址上传原始心电文件。示例如下:
curl -X PUT --location "https://ecgdata-1255716792.cos.ap-shanghai.myqcloud.com/openapi/2039546102478438400/2604021132295727.BINARY16?sign=xxx" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-binary @/path/to/your/file.BINARY16
说明:
- 将命令中的 URL 替换为 Step 1 接口实际返回的上传地址。
- 将
/path/to/your/file.BINARY16替换为本地待上传文件路径。 - 文件扩展名应与申请上传地址时传入的
fileType保持一致。
上传文件格式说明
当前支持以下两种二进制文件格式:
BINARY16 格式(单导联)
- 2 个字节为一组,表示 1 个 ECG 信号点。
- 第 1、2 字节表示第 1 个信号点。
- 第 3、4 字节表示第 2 个信号点。
- 以此类推。
- 字节按大端有符号数转换为十进制值。
字节1 字节2 -> 第1个信号点
字节3 字节4 -> 第2个信号点
字节5 字节6 -> 第3个信号点
...
BIN3_16 格式(三导联)
- 6 个字节为一组。
- 第 1、2 字节表示第 1 个导联的第 1 个点。
- 第 3、4 字节表示第 2 个导联的第 1 个点。
- 第 5、6 字节表示第 3 个导联的第 1 个点。
- 后续按相同顺序依次表示下一采样点的三导联数据。
- 字节按大端有符号数转换为十进制值。
字节1 字节2 -> 第1导联第1个点
字节3 字节4 -> 第2导联第1个点
字节5 字节6 -> 第3导联第1个点
字节7 字节8 -> 第1导联第2个点
字节9 字节10 -> 第2导联第2个点
字节11 字节12 -> 第3导联第2个点
...
Step 2:提交快速分析任务
POST /api/v1/advanced/ecg/holter/fast/submit
文件上传完成后,调用该接口提交分析任务。请求体与长程分析提交接口一致。
请求体参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
fileUrl | string | 是 | Step 1 返回的文件上传地址,原样回传 |
adcGain | number | 是 | 增益系数,不能为 0 |
adcZero | number | 是 | 基线电压 |
sampleRate | integer | 是 | 采样率,取值范围 1 ~ 10000 |
deviceId | string | 否 | 设备 ID |
startTime | string | 否 | 记录开始时间,格式必须为 yyyy-MM-dd HH:mm:ss |
subject | object | 否 | 受检者信息 |
subject 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
name | string | 否 | 姓名,最长 20 个字符 |
age | integer | 否 | 年龄 |
gender | string | 否 | 性别,最长 5 个字符 |
单条记录的时长不得超过 24 小时,超出的记录请拆分后分次提交。
结果中的位置(idx)需要配合 startTime 换算为实际时刻,建议传入。
请求示例
curl -X POST "https://api.heartvoice.com.cn/api/v1/advanced/ecg/holter/fast/submit" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"fileUrl": "https://ecgdata-1255716792.cos.ap-shanghai.myqcloud.com/openapi/2039546102478438400/2604021132295727.BINARY16?sign=xxx",
"adcGain": 1000,
"adcZero": 0,
"sampleRate": 256,
"deviceId": "DEVICE_001",
"startTime": "2026-04-02 10:00:00",
"subject": {
"name": "张三",
"age": 56,
"gender": "男"
}
}'
响应示例
{
"errorCode": "0",
"msg": "成功",
"data": "2092896927501512704"
}
说明
- 返回值
data为本次快速分析的任务 ID(taskId)。 taskId是字符串形式的 19 位数字,请勿按数值类型解析(JavaScript 等语言会丢失精度)。- 接口返回成功表示任务已受理,不代表分析已完成,需通过 Step 3 查询结果。
错误响应
| HTTP 状态 | errorCode | 说明 | 建议处理 |
|---|---|---|---|
| 400 | 000002 | 必填参数缺失或取值不合法 | 依据 msg 修正后重试 |
| 400 | 000008 | 参数取值不合法,或文件不可读取、记录时长超过 24 小时 | 依据 msg 修正后重试 |
| 429 | 000006 | 请求过于频繁 | 降低请求频率后重试 |
| 429 | 000014 | 分析服务繁忙 | 稍后重试 |
| 429 | 000015 | 当前账号同时进行的分析任务过多 | 待已提交的任务完成后再提交 |
| 500 | 000017 | 分析服务暂不可用 | 稍后重试 |
Step 3:查询快速分析结果
GET /api/v1/advanced/ecg/holter/fast/result/:taskId
根据提交接口返回的任务 ID 轮询任务状态与结果。请将路径中的 :taskId 替换为实际任务 ID。
路径参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
taskId | string | 是 | 提交接口返回的任务 ID |
请求示例
curl -X GET "https://api.heartvoice.com.cn/api/v1/advanced/ecg/holter/fast/result/2092896927501512704" \
-H "Authorization: Bearer YOUR_API_KEY"
返回字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
status | string | 任务状态,取值见下表 |
result | object | 分析结果,仅 status = SUCCESS 时非空 |
status 取值
| 取值 | 含义 | 是否继续轮询 |
|---|---|---|
PENDING | 排队中 | 是 |
RUNNING | 分析中 | 是 |
SUCCESS | 分析完成 | 否,result 即为结果 |
FAILED | 分析失败 | 否 |
未分析完成示例
{
"errorCode": "0",
"msg": "成功",
"data": {
"status": "PENDING",
"result": null
}
}
分析完成示例
{
"errorCode": "0",
"msg": "成功",
"data": {
"status": "SUCCESS",
"result": {
"totalValidBeats": 96064,
"diagDescription": "记录全过程为窦性心律,心率介于40~74次/分,平均心率46次/分,全程可见窦性心动过缓。偶发房性早搏,单发房早154次,短阵房速1阵。偶发室性早搏,单发室早74次。可见心房颤动。",
"hr": {
"avgHr": 46,
"minHr": 40,
"minHrIdx": 4972695,
"maxHr": 74,
"maxHrIdx": 1165976,
"minTopHr": [{ "hr": 40, "idx": 6124437 }, { "hr": 40, "idx": 4972695 }],
"maxTopHr": [{ "hr": 74, "idx": 1165976 }, { "hr": 67, "idx": 6381351 }]
},
"SNT": null,
"SNB": {
"totalDuration": 10300.945,
"maxBeatCount": 684,
"maxDuration": 881,
"idx": [1471291, 1647626]
},
"labels": ["SNB", "PVC", "PAC", "AF"],
"labelIdx": {
"AF": [{ "idx": [4612620, 4679166] }],
"SNB": [{ "idx": [1071129, 1074694] }, { "idx": [1076492, 1079677] }]
},
"premature": {
"totalPAC": 154, "singlePAC": 154,
"totalSVT": 1, "totalSVTCnt": 1,
"totalPVC": 74, "singlePVC": 74,
"totalPJC": 0, "singlePJC": 0
}
}
}
}
上例中
premature为节选,实际返回全部字段,详见字段说明。
分析失败示例
{
"errorCode": "0",
"msg": "成功",
"data": {
"status": "FAILED",
"result": null
}
}
错误响应
| HTTP 状态 | errorCode | 说明 |
|---|---|---|
| 400 | 000016 | 任务不存在,或该任务不属于当前 API Key |
| 429 | 000006 | 请求过于频繁 |
只要查询请求本身被正确处理,响应信封的 errorCode 就是 "0"。任务失败体现在 data.status = "FAILED",而不是信封的错误码,请不要把 status = FAILED 当作查询失败去重试。
轮询建议
- 提交后等待 5 秒再发起第一次查询,之后每 10 秒查询一次。
- 超过 1 分钟仍未完成时,将间隔拉长到 30 秒。
- 记录越长分析越慢,24 小时量级的记录需要数十秒;服务繁忙时耗时会进一步增加,建议总超时不低于 10 分钟。
- 同时跟踪多个任务时请进一步拉长间隔,避免触发
000006频率限制。
请勿以短于 5 秒的间隔轮询。高频轮询不会让结果更早返回,只会占用服务资源并触发频率限制。
轮询示例(间隔从 5 秒逐步拉长到 30 秒):
INTERVAL=5
while true; do
sleep $INTERVAL
RESP=$(curl -s -H "Authorization: Bearer YOUR_API_KEY" \
"https://api.heartvoice.com.cn/api/v1/advanced/ecg/holter/fast/result/$TASK_ID")
STATUS=$(echo "$RESP" | jq -r '.data.status')
case "$STATUS" in
SUCCESS) echo "$RESP" | jq '.data.result'; break ;;
FAILED) echo "分析失败"; break ;;
*) [ $INTERVAL -lt 30 ] && INTERVAL=$((INTERVAL + 5)) ;;
esac
done
长程快速分析结果 JSON 字段说明
与长程分析通道不同,快速分析的 data.result 已经是 JSON 对象,直接读取即可,无需再做一次反序列化。
阅读说明
📌 顶层字段固定出现
totalValidBeats、diagDescription、hr、SNT、SNB、labels、labelIdx、premature这 8 个顶层字段每次都会返回。本次未发生的项以null(如SNT)、空数组或空对象呈现,而不是省略该字段。
📌 位置(idx) 字段名中带
Idx的表示事件在记录中的位置,单位为采样点序号;区间用[起点, 终点]表示。
📌 位置换算时间
时刻 = 记录开始时间 + idx ÷ 采样率(秒)。采样率以提交时传入的sampleRate为准,记录开始时间以提交时传入的startTime为准。
一、字段总览
| 字段 | 类型 | 说明 | 详见 |
|---|---|---|---|
totalValidBeats | 整数 | 去除干扰后的有效心搏总数 | — |
diagDescription | 字符串 | 根据节律标签与心率自动生成的诊断结论文字 | — |
hr | 对象 | 整段记录的心率统计 | 2.1 |
SNT | 对象 / null | 窦性心动过速统计,本次无则为 null | 2.2 |
SNB | 对象 / null | 窦性心动过缓统计,本次无则为 null | 2.2 |
labels | 数组 | 本次检出的节律类型集合 | 2.3 |
labelIdx | 映射对象 | 各节律出现的位置区间 | 2.3 |
premature | 对象 | 各类早搏 / 异位心律统计 | 2.4 |
结构示意 :
result(对象)
├─ totalValidBeats / diagDescription
├─ hr ──────────────► { avgHr, minHr, maxHr, minTopHr[], maxTopHr[] }
├─ SNT / SNB ───────► { totalDuration, maxBeatCount, maxDuration, idx[] } 或 null
├─ labels[] / labelIdx{ 节律 → [ {idx} ] }
└─ premature ───────► { 室性 / 房性 / 交界性 早搏统计 }
二、字段详解
2.1 hr(心率统计)
汇总整段记录的心率信息。
| 字段 | 类型 | 说明 |
|---|---|---|
avgHr | 整数(次/分) | 平均心率 |
minHr | 整数(次/分) | 最慢心率 |
minHrIdx | 整数 | 最慢心率出现的位置 |
maxHr | 整数(次/分) | 最快心率 |
maxHrIdx | 整数 | 最快心率出现的位置 |
minTopHr | 数组 | 最慢的前 5 个心率,元素结构见下 |
maxTopHr | 数组 | 最快的前 5 个心率,元素结构见下 |
minTopHr / maxTopHr 数组元素:
| 字段 | 类型 | 说明 |
|---|---|---|
hr | 整数(次/分) | 心率 |
idx | 整数 | 该心率出现的位置 |
数据无效时,
avgHr/minHr/maxHr/minHrIdx/maxHrIdx均为null,两个 Top 数组为空。
2.2 SNT / SNB(窦性心动过速 / 过缓)
SNT(过速)、SNB(过缓)结构相同,本次记录若无则该字段为 null。
| 字段 | 类型 | 说明 |
|---|---|---|
totalDuration | 小数(秒) | 总持续时间 |
maxBeatCount | 整数 | 最长一阵连续发作的心搏数 |
maxDuration | 整数(秒) | 最长一阵连续发作的持续时间 |
idx | [起点, 终点] | 最长一阵的起止位置 |
2.3 labels / labelIdx(异常标签)
二者共同描述"AI算法检出了哪些异常,并从中选择出代表性的心电图片段发生的时间点"。
| 字段 | 类型 | 说明 |
|---|---|---|
labels | 数组 | 本次检出的异常类型集合(取值见附录),无异常时为空数组 |
labelIdx | 映射对象 | 键为异常类型,值为该异常出现的区间列表(数量较多时会挑选具有代表性的发生点),无异常时为空对象 |
labelIdx 值(区间列表)的元素:
| 字段 | 类型 | 说明 |
|---|---|---|
idx | [起点, 终点] | 该次出现的起止位置 |
2.4 premature(早搏统计)
统计室性、房性、交界性三类早搏及其衍生节律。该对象的字段每次都会完整返回,本次记录若无则计数为 0。
房性早搏 PAC:
| 字段 | 类型 | 说明 |
|---|---|---|
totalPAC | 整数 | 房性早搏总数 |
singlePAC | 整数 | 单发房早次数 |
pairedPAC | 整数 | 成对房早次数 |
pairedPACCnt | 整数 | 成对房早阵数 |
bigeminyPAC | 整数 | 房早二联律次数 |
bigeminyPACCnt | 整数 | 房早二联律阵数 |
triadPAC | 整数 | 房早三联律次数 |
triadPACCnt | 整数 | 房早三联律阵数 |
totalSVT | 整数 | 室上性(房性)心动过速次数 |
totalSVTCnt | 整数 | 室上性心动过速阵数 |
室性早搏 PVC:
| 字段 | 类型 | 说明 |
|---|---|---|
totalPVC | 整数 | 室性早搏总数 |
singlePVC | 整数 | 单发室早次数 |
pairedPVC | 整数 | 成对室早次数 |
pairedPVCCnt | 整数 | 成对室早阵数 |
bigeminyPVC | 整数 | 室早二联律次数 |
bigeminyPVCCnt | 整数 | 室早二联律阵数 |
triadPVC | 整数 | 室早三联律次数 |
triadPVCCnt | 整数 | 室早三联律阵数 |
totalVT | 整数 | 室性心动过速次数 |
totalVTCnt | 整数 | 室性心动过速阵数 |
交界性早搏 PJC:
| 字段 | 类型 | 说明 |
|---|---|---|
totalPJC | 整数 | 交界性早搏总数 |
singlePJC | 整数 | 单发交界性早搏次数 |
pairedPJC | 整数 | 成对交界性早搏次数 |
pairedPJCCnt | 整数 | 成对交界性早搏阵数 |
bigeminyPJC | 整数 | 交界性早搏二联律次数 |
bigeminyPJCCnt | 整数 | 交界性早搏二联律阵数 |
triadPJC | 整数 | 交界性早搏三联律次数 |
triadPJCCnt | 整数 | 交界性早搏三联律阵数 |
totalJT | 整数 | 交界性心动过速次数 |
totalJTCnt | 整数 | 交界性心动过速阵数 |
三、完整 JSON 示例
3.1 正常结果
为节省篇幅,
labelIdx的区间列表仅保留前若干项。
{
"totalValidBeats": 96064,
"diagDescription": "记录全过程为窦性心律,心率介于40~74次/分,平均心率46次/分,全程可见窦性心动过缓。偶发房性早搏,单发房早154次,短阵房速1阵。偶发室性早搏,单发室早74次。可见心房颤动。",
"hr": {
"avgHr": 46,
"minHr": 40,
"minHrIdx": 4972695,
"maxHr": 74,
"maxHrIdx": 1165976,
"minTopHr": [
{ "hr": 40, "idx": 6124437 },
{ "hr": 40, "idx": 4972695 },
{ "hr": 40, "idx": 5036199 },
{ "hr": 40, "idx": 5416000 },
{ "hr": 40, "idx": 5432704 }
],
"maxTopHr": [
{ "hr": 74, "idx": 1165976 },
{ "hr": 67, "idx": 6381351 },
{ "hr": 61, "idx": 5492136 },
{ "hr": 61, "idx": 6294038 },
{ "hr": 60, "idx": 6373840 }
]
},
"SNT": null,
"SNB": {
"totalDuration": 10300.945,
"maxBeatCount": 684,
"maxDuration": 881,
"idx": [1471291, 1647626]
},
"labels": ["SNB", "PVC", "PAC", "AF"],
"labelIdx": {
"AF": [
{ "idx": [4612620, 4679166] }
],
"SNB": [
{ "idx": [1071129, 1074694] },
{ "idx": [1076492, 1079677] },
{ "idx": [1082027, 1163252] }
]
},
"premature": {
"totalPAC": 154,
"singlePAC": 154,
"pairedPAC": 0,
"pairedPACCnt": 0,
"bigeminyPAC": 0,
"bigeminyPACCnt": 0,
"triadPAC": 0,
"triadPACCnt": 0,
"totalSVT": 1,
"totalSVTCnt": 1,
"totalPVC": 74,
"singlePVC": 74,
"pairedPVC": 0,
"pairedPVCCnt": 0,
"bigeminyPVC": 0,
"bigeminyPVCCnt": 0,
"triadPVC": 0,
"triadPVCCnt": 0,
"totalVT": 0,
"totalVTCnt": 0,
"totalPJC": 0,
"singlePJC": 0,
"pairedPJC": 0,
"pairedPJCCnt": 0,
"bigeminyPJC": 0,
"bigeminyPJCCnt": 0,
"triadPJC": 0,
"triadPJCCnt": 0,
"totalJT": 0,
"totalJTCnt": 0
}
}
3.2 无效数据结果
{
"totalValidBeats": null,
"diagDescription": "无效数据,请重新采集",
"hr": null,
"SNT": null,
"SNB": null,
"labels": null,
"labelIdx": null,
"premature": null
}
附录:节律标签字典
labels 与 labelIdx 的键取自下表节律标签编码:
| 编码 | 含义 |
|---|---|
SN | 窦性心律 |
N | 正常心电图 |
SNA | 窦性心律不齐 |
PVC | 室性早搏 |
PAC | 房性早搏 |
PJC | 交界性早搏 |
AFL | 心房扑动 |
AF | 心房颤动 |
VFL | 心室扑动 |
VF | 心室颤动 |
WPW | WPW |
LGL | LGL |
VE | 室性逸搏 |
AE | 房性逸搏 |
JE | 交界性逸搏 |
AVBI | 一度房室传导阻滞 |
AVBII |