Files
2026-11-12 16:11:43 +08:00
..
2026-11-12 16:11:43 +08:00
更
2026-10-22 11:12:16 +08:00
2026-11-12 16:11:43 +08:00
2026-11-12 16:11:43 +08:00
更
2026-10-22 11:12:16 +08:00
更
2026-10-22 11:12:16 +08:00
更
2026-10-22 11:12:16 +08:00
更
2026-10-22 11:12:16 +08:00
更
2026-10-22 11:12:16 +08:00

Doctor Video Companion

这是桌面端专用的最小 Vue 3 / Vite 视频页面。它与 admin 的独立视频组件保持同一条 SDK 主链,直接使用固定版本 @trtc/calls-uikit-vue@4.4.6。

构建

cd video_companion
npm ci
npm run build

构建产物位于 video_companion/dist/。Vite 使用相对资源路径,因此产物既能由 HTTPS 托管,也能由 QtWebEngine 从本地安装目录加载。

桌面端当前只在隔离的 QtWebEngine 中加载此页面。页面不会自行向后端领取通话票据,因此在后端提供服务端签发的一次性 handoff 前,系统浏览器模式与自动浏览器降级均被禁用。

宿主契约

截屏按当前患者的用户 ID 匹配 SDK 远端视频,通过 Canvas 提取该视频的原始画面,保持比例、最长边不超过 1920 像素。画面不含医生小窗、按钮、字幕、姓名或侧栏,也不受大小窗切换、CSS 裁切或镜像影响。远端摄像头关闭、帧不可用或身份不匹配时明确报错,不回退到整窗截屏。

前端通过 qtVideoBridge.preparePatientScreenshot(targetUserId, dataUrl, callback) 将 JPEG 交给宿主校验。宿主核对当前通话、患者身份及图片实际格式和尺寸,注册同一张图供 AI 分析,返回包含 dataUrl 或 error 的 JSON;注册本身不上传也不保存。新版前端和桌面宿主需要同步更新。

截取后立即显示预览,通过 analyzeTongueScreenshotModel(requestId, dataUrl, model) 同时提交千问(qwen)和 GPT(openai)分析同一张 JPEG。两者使用现有 AI 服务中各自配置的模型应用;每个模型有独立请求 UUID、结果和错误状态,先完成的可先查看,切换标签直接读取缓存,重试仅重新调用当前模型。分析仅使用本张截图,不读取病历,不写诊单;只有医生点击“确认并上传”才调用 saveScreenshot 保存患者舌像资料。该功能需要同步更新桌面宿主、前端资源及服务端 tcm.diagnosis/aiTongueScreenshot 接口,并配置两个支持图片的模型应用。

分析响应通过 doctorConsultation.tongueScreenshotResult 回传,绑定请求 UUID、模型、当前诊单和图片 SHA-256。响应包含可见舌象与 tcm_diagnosis 中医诊断参考:初步证候、引用本次舌象的依据、需要核实的问题和缺失资料;不足以辨证时明确返回 insufficient。图片不清晰或没有可辨认舌象时返回重拍提示,不生成特征或证候。关闭预览或切换上下文后丢弃两个模型的迟到结果;在途网络请求仍受独立超时限制。AI 结果不自动写入病历或发送给患者。

每个模型请求共享 50 秒服务端总时限(含上传),桌面桥接等待上限为 65 秒。首次成功取得字符串答案但未通过结果契约校验时,若总时限还剩至少 3 秒,服务端会使用同一模型、同一已上传图片和匿名请求用户执行一次格式纠正;只追加固定规则,不回传原答案,不读取历史,也不重新上传或切换模型。纠正结果必须通过同一套完整校验,仍不合格就返回安全错误。上传、HTTP、鉴权、模型接口配置、超时、外层响应格式或答案超限错误均不触发纠正;首次结果合格只调用模型一次。

预览显示后发送 screenshot-preview 通知(visible: true/false)。宿主将小窗临时放大到正常窗口尺寸,取消、提交或结束通话后恢复原位置和大小;先抓图再放大,避免改变截图内容。图片按预览区域等比例放大显示。

打开诊单后的通话小窗,标题栏“×”用于恢复原大窗,通话与录音继续。结束视频、正常大窗关闭、退出登录及程序退出仍走完整的挂断和录音收尾流程。

页面加载后会暴露:

window.doctorCall.start({
  SDKAppID: 1400000000, // 也接受 sdkAppId
  userID: 'doctor_42',  // 也接受 userId
  userSig: '<后端短时票据>',
  targetUserId: 'patient_8', // 也接受 patientUserId
  diagnosisId: 123,
})

await window.doctorCall.hangup()

userSig 必须由业务后端签发。此页面不会生成 UserSig,也不接受或使用 SDKSecretKey。

状态、错误与挂断消息优先调用 window.qtVideoBridge.notify(JSON.stringify(message))。没有 Qt bridge 时,页面使用 postMessage 通知父窗口或 opener;都不可用时只输出不含票据的控制台状态。