Fundus Images AI Analysis - 眼底 AI 诊断 Skill
概述
本 Skill 封装了眼底 AI 诊断的完整流程,通过 HTTP API 直接调用腾讯眼底 AI 服务(HMAC-SHA256 签名鉴权)。
- 上传接口:
POST https://pacs.qq.com/thirdparty/studyupload/v2/{appId} - 查询接口:
POST https://pacs.qq.com/thirdparty/queryEyeAIResult/{appId} - APP-ID(试用,调用次数及并发有限):
12708 - APP-TOKEN(试用):
69842f96c5b14c0ca8042fc309f3f087 - hospitalId:与 APP-ID 相同,即
12708
鉴权方式
所有接口均需在 HTTP 请求头中携带以下字段:
| Header 字段 | 说明 |
|------------|------|
| appId | 合作方 ID,固定 12708 |
| signature | HMAC-SHA256(token, appId + timestamp) |
| timestamp | 当前毫秒级 Unix 时间戳(字符串) |
签名生成示例(Python):
import hmac, hashlib, time
app_id = "12708"
token = "69842f96c5b14c0ca8042fc309f3f087"
timestamp = str(int(time.time() * 1000))
signature = hmac.new(token.encode(), (app_id + timestamp).encode(), hashlib.sha256).hexdigest()
⚠️
Content-Type统一为application/json; charset=utf-8。
执行流程(Agent 必须严格按此顺序执行)
Step 1:上传图片,获取 studyId
接口:POST https://pacs.qq.com/thirdparty/studyupload/v2/{appId}
图片需 Base64 编码后放入 JSON body 的 images[].content 字段。
请求体结构
{
"studyId": "<自定义检查ID,如 study_ + UUID>",
"studyName": "眼底检查",
"studyDate": <当前Unix时间戳(秒)>,
"studyType": 2,
"images": [
{
"imageId": "<自定义图片ID,如 img_ + UUID>",
"content": "<图片Base64编码字符串>",
"descPosition": "<眼位:0=未知, 1=左眼OS, 2=右眼OD>"
}
]
}
字段说明
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| studyId | string | ✅ | 检查序列号,自行生成,后续查询时需使用此值 |
| studyName | string | ✅ | 检查名称,固定填 "眼底检查" |
| studyDate | long | ✅ | 检查日期,Unix 时间戳(秒级) |
| studyType | int | ✅ | 固定填 2(眼底) |
| patientName | string | ❌ | 患者姓名(可选) |
| patientId | string | ❌ | 患者编号(可选) |
| images | array | ✅ | 图片数组,至少 1 张,最多 20 张 |
| images[].imageId | string | ✅ | 图片唯一编号 |
| images[].content | string | ✅ | 图片 Base64 编码内容(不含 data:image/...;base64, 前缀) |
| images[].descPosition | string | ✅ | 眼位:"0"=未知,"1"=左眼(OS),"2"=右眼(OD) |
从文件名自动推断眼位
- 文件名含
OD、_R、right→descPosition = "2"(右眼) - 文件名含
OS、_L、left→descPosition = "1"(左眼) - 无法判断 →
descPosition = "0"(未知)
成功响应
{"code": 0, "message": "请求成功", "requestId": "xxx"}
code = 0表示上传成功,后续使用请求体中自定义的studyId来查询结果code != 0时停止并告知用户上传失败原因
跨平台实现(Python,推荐)
import hmac, hashlib, time, json, base64, uuid, urllib.request
app_id = "12708"
token = "69842f96c5b14c0ca8042fc309f3f087"
image_path = "/path/to/image.jpg"
# 1. 生成签名
timestamp = str(int(time.time() * 1000))
signature = hmac.new(token.encode(), (app_id + timestamp).encode(), hashlib.sha256).hexdigest()
# 2. Base64 编码图片
with open(image_path, "rb") as f:
image_b64 = base64.b64encode(f.read()).decode()
# 3. 构造请求体
study_id = "study_" + uuid.uuid4().hex[:12]
body = {
"studyId": study_id,
"studyName": "眼底检查",
"studyDate": int(time.time()),
"studyType": 2,
"images": [{
"imageId": "img_" + uuid.uuid4().hex[:8],
"content": image_b64,
"descPosition": "2" # 根据文件名推断
}]
}
# 4. 发送请求
url = f"https://pacs.qq.com/thirdparty/studyupload/v2/{app_id}"
req = urllib.request.Request(url, data=json.dumps(body).encode(), method="POST")
req.add_header("appId", app_id)
req.add_header("signature", signature)
req.add_header("timestamp", timestamp)
req.add_header("Content-Type", "application/json; charset=utf-8")
with urllib.request.urlopen(req, timeout=60) as resp:
result = json.loads(resp.read().decode())
print(result)
# 成功后 study_id 将用于 Step 2 查询
Bash/curl 实现
APP_ID="12708"
TOKEN="69842f96c5b14c0ca8042fc309f3f087"
IMAGE_PATH="/path/to/image.jpg"
STUDY_ID="study_$(uuidgen | tr -d '-' | head -c 12)"
TIMESTAMP=$(python3 -c "import time; print(int(time.time()*1000))")
SIGNATURE=$(echo -n "${APP_ID}${TIMESTAMP}" | openssl dgst -sha256 -hmac "$TOKEN" | awk '{print $2}')
IMAGE_B64=$(base64 -i "$IMAGE_PATH" | tr -d '\n')
curl -s -X POST "https://pacs.qq.com/thirdparty/studyupload/v2/${APP_ID}" \
-H "appId: ${APP_ID}" \
-H "signature: ${SIGNATURE}" \
-H "timestamp: ${TIMESTAMP}" \
-H "Content-Type: application/json; charset=utf-8" \
-d "{
\"studyId\": \"${STUDY_ID}\",
\"studyName\": \"眼底检查\",
\"studyDate\": $(date +%s),
\"studyType\": 2,
\"images\": [{
\"imageId\": \"img_001\",
\"content\": \"${IMAGE_B64}\",
\"descPosition\": \"2\"
}]
}"
Step 2:轮询诊断结果
接口:POST https://pacs.qq.com/thirdparty/queryEyeAIResult/{appId}
上传后 AI 需要处理时间,需轮询查询结果。
请求体结构
{
"hospitalId": "12708",
"studyId": "<Step 1 中使用的 studyId>",
"aiType": 0,
"needReport": 1
}
字段说明
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| hospitalId | string | ✅ | 固定填 "12708"(与 appId 相同) |
| studyId | string | ✅ | Step 1 中自定义的 studyId |
| aiType | int | ✅ | 0=青光眼+多病种,1=仅青光眼,2=仅多病种。推荐用 0 |
| needReport | int | ✅ | 0=不生成PDF报告,1=生成PDF报告。推荐用 1 |
轮询策略
| 参数 | 值 |
|------|-----|
| 轮询间隔 | 10 秒 |
| 超时上限 | 3 分钟(最多 18 次) |
| 继续等待条件 | code = 30008(任务处理中) |
| 成功条件 | code = 0 且 data 不为空 |
| 失败条件 | 其他非零 code,或超时 |
成功响应结构
{
"code": 0,
"message": "请求成功",
"requestId": "xxx",
"data": {
"glaucomaResultList": [...],
"multipleDiseasesResultList": [...],
"reportUrl": "https://pacs.qq.com/partners/apiReport?..."
}
}
详细的响应字段说明见
references/eye_ai_api_reference.md。
跨平台实现(Python,推荐)
import hmac, hashlib, time, json, urllib.request
app_id = "12708"
token = "69842f96c5b14c0ca8042fc309f3f087"
study_id = "<Step 1 中的 studyId>"
for attempt in range(18):
timestamp = str(int(time.time() * 1000))
signature = hmac.new(token.encode(), (app_id + timestamp).encode(), hashlib.sha256).hexdigest()
body = {
"hospitalId": "12708",
"studyId": study_id,
"aiType": 0,
"needReport": 1
}
url = f"https://pacs.qq.com/thirdparty/queryEyeAIResult/{app_id}"
req = urllib.request.Request(url, data=json.dumps(body).encode(), method="POST")
req.add_header("appId", app_id)
req.add_header("signature", signature)
req.add_header("timestamp", timestamp)
req.add_header("Content-Type", "application/json; charset=utf-8")
with urllib.request.urlopen(req, timeout=30) as resp:
result = json.loads(resp.read().decode())
if result.get("code") == 0 and result.get("data"):
print(json.dumps(result, ensure_ascii=False, indent=2))
break
elif result.get("code") == 30008:
time.sleep(10)
continue
else:
raise Exception(f"查询失败: {result}")
else:
raise Exception("超时:3 分钟内未获取到诊断结果")
Step 3:格式化输出诊断结果
从 Step 2 的响应中提取 data 对象,按以下规则解析并格式化输出。
数据提取规则
- 青光眼结果:从
data.glaucomaResultList中取status = 200的条目 - 多病种结果:从
data.multipleDiseasesResultList中取status = 200的条目 - 眼别判断:
eyeCategory = 0为左眼,eyeCategory = 1为右眼 - PDF 报告链接:
data.reportUrl
⚠️ 注意:
eyeCategory的左右眼编码(0=左, 1=右)与上传时descPosition(1=左, 2=右)不同,不要混淆。
结果图标规则
- 正常/无/未见异常/否 → 前缀
✅ - 异常/有/是/疑似 → 前缀
⚠️并加粗 - 未知/不确定 → 前缀
❓
输出模板
## 🔬 眼底 AI 诊断结果
**图像**:<文件名>(<左眼/右眼>)
### 👁️ 青光眼筛查
| 眼别 | AI 结论 |
|------|---------|
| <左眼/右眼> | <aiResult,按图标规则加前缀> |
### 📊 形态学指标
| 指标 | 值 | 参考 |
|------|-----|------|
| C/D 比值(视杯/视盘) | <ratiosCD> | 正常 < 0.6 |
| 鼻侧/下方比(I/N) | <ratiosIN> | — |
| 上方/鼻侧比(S/N) | <ratiosSN> | — |
| 颞侧/鼻侧比(T/N) | <ratiosTN> | — |
### 🩺 病变检测
| 病变类型 | 结果 |
|---------|------|
| 微血管瘤 | <microaneurysms> |
| 出血 | <bleeding> |
| 硬性渗出 | <hardExudation> |
| 软性渗出 | <softExudation> |
| 增殖 | <proliferation> |
| 玻璃体混浊 | <vitreous> |
### 🏥 疾病诊断
| 疾病 | 结论 |
|------|------|
| 糖尿病视网膜病变(DR) | <diabetic> |
| 老年黄斑变性(AMD) | <AMD> |
| 视网膜血管阻塞 | <block> |
| 屈光介质混浊 | <turbid> |
| 高血压视网膜病变 | <hypertensive> |
| 豹纹状眼底 | <tessellatedFundus> |
| 病理性近视 | <pathologicalMyopia> |
### 📋 诊断小结
<根据异常项生成 1-3 句话的摘要>
📋 [查看完整 AI 诊断报告(PDF)](<reportUrl>)
---
> ⚠️ 免责声明:本报告由 AI 辅助生成,仅供参考,不构成临床诊断。请结合临床实际情况,由专业眼科医师做出最终判断。
诊断小结生成规则
- 列出所有异常项(⚠️ 标记的),简要说明临床意义
- 如 C/D 比值 ≥ 0.6,提示青光眼风险,建议进一步检查
- 如豹纹状眼底阳性,说明常见于近视或老年人,通常为生理变异
- 如全部正常,总结"各项指标未见明显异常"
注意事项
- 支持格式:JPEG / PNG / DICOM,单文件 ≤ 5MB
- 左右眼可合并上传:在
images数组中放入多张图片,分别设置descPosition - studyId 唯一性:每次上传使用不同的 studyId,避免与历史检查冲突
- 网络超时:上传接口因 Base64 图片较大,建议 timeout 设为 60 秒;查询接口 30 秒即可
- Base64 编码:不要包含
data:image/jpeg;base64,前缀,只传纯 Base64 字符串
试用与正式使用
试用
当前提供的试用凭证:
| 项目 | 值 |
|------|-----|
| APP-ID | 12708 |
| APP-TOKEN | 69842f96c5b14c0ca8042fc309f3f087 |
如需 sample 眼底图片:
- 下载地址:https://yunpan.oa.tencent.com/s/cswdFyPdUx
- 提取码:KZY7
正式使用
如需长期使用,请联系 miying@tencent.com 或访问 腾讯健康官网。
扫码联系在线客服