Flutter + FunASR 透析管理系统语音输入技术方案

Flutter + FunASR 透析管理系统语音输入技术方案

整理时间: 2026-02-16 08:38
来源: 群聊消息
整理人: AI助手

摘要

本文档在原技术方案基础上,进一步细化了技术选型:采用 Flutter Desktop (Windows) 作为客户端框架,配合 FunASR 语音识别和 Kimi/Minimax 云端 LLM,通过浏览器插件方案实现精准填表。文档还详细分析了开发过程中可能遇到的挑战及应对策略。


一、技术架构(更新版)

1.1 整体架构图

┌─────────────────────────────────────────────────────────────────┐
│                        医生工作站                                  │
│                                                                 │
│  ┌─────────────────┐    ┌─────────────────────────────────────┐ │
│  │  透析管理系统    │    │       Flutter 客户端                 │ │
│  │  (BS 浏览器)    │◄───│  ┌─────────────────────────────┐   │ │
│  │                 │    │  │ 悬浮球 UI / 全局热键          │   │ │
│  │  [干体重]      │    │  │ 录音控制 (record)             │   │ │
│  │  [收缩压]      │    │  │ WebSocket Server (本地通信)   │   │ │
│  │  [舒张压]      │    │  └──────────────┬────────────────┘   │ │
│  │  ...            │    │                 │                    │ │
│  └─────────────────┘    │                 │ JSON              │ │
│                         │                 ▼                    │ │
│  ┌─────────────────┐    │  ┌─────────────────────────────┐     │ │
│  │ Chrome 插件    │◄───┤  │ FunASR API (本地/内网)    │     │ │
│  │ (接收 JSON    │    │  │ 语音 → 文字                 │     │ │
│  │  DOM 填充)    │    │  └──────────────┬──────────────┘     │ │
│  └─────────────────┘    │                 │                    │ │
│                         │                 ▼                    │ │
│                         │  ┌─────────────────────────────┐     │ │
│                         │  │ Kimi/Minimax API (云端)    │     │ │
│                         │  │ 文字 → 结构化 JSON         │     │ │
│                         │  └─────────────────────────────┘     │ │
│                         └─────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

1.2 核心通信链路

Flutter 运行在 OS 层,浏览器运行在沙盒中,需要通过本地 WebSocket 通信:

医生点击快捷键(Flutter 捕获)
        ↓
开始录音(Flutter record 模块)
        ↓
录音结束 → 发送给 FunASR API → 得到文字
        ↓
发送文字给 Kimi/Minimax API → 得到 JSON 指标
        ↓
Flutter 通过 WebSocket 将 JSON 推送给浏览器插件
        ↓
插件通过 JavaScript 操作 DOM 自动填充表单

二、技术栈清单

模块 推荐技术 说明
GUI Flutter Desktop (Windows) 跨平台能力强,资源占用远低于 Electron
全局热键 hotkey_manager 监听快捷键触发录音
录音控制 record 支持 WebM/M4A/WAV 格式
本地通信 shelf_web_socket 在 Flutter 里开本地 WebSocket Server
ASR FunASR (阿里开源) 通过 runtime-SDK 封装为 API
LLM Kimi 或 Minimax 云端处理结构化提取
浏览器插件 自研 Chrome Extension 精准 DOM 填充

三、FunASR 方案详解

3.1 为什么选择 FunASR?

特性 说明
工业级性能 Paraformer 模型在中文医疗术语识别上非常精准
私有化能力 支持 Docker 部署,可搬到内网服务器,符合透析数据敏感要求
流式识别 支持边说边出文字,降低延迟感知
开源免费 社区活跃,持续更新

3.2 部署方式

方式 A:本地部署(推荐医疗场景)

  • 部署在医院内网服务器
  • 数据不出院,符合隐私要求
  • 需要 GPU 支持(RTX 3060+)

方式 B:封装为后端 API

  • 使用 FunASR runtime-SDK 封装
  • Flutter 通过 HTTP 调用
  • 延迟更低,体验更好

四、云端 LLM 选型

4.1 Kimi vs Minimax 对比

特性 Kimi Minimax
长文本处理 极强(128K+)
指令遵循 优秀 优秀
响应速度 中等
JSON 输出 稳定 稳定
适合场景 病历归纳、复杂对话 快速提取、实时响应

4.2 结构化提取 Prompt 示例

你是一个透析记录助手。请从这段话中提取以下字段:

字段说明:
- uf: 超滤量 (单位:kg 或 ml)
- bp_high: 收缩压 (单位:mmHg)
- bp_low: 舒张压 (单位:mmHg)
- flow: 透析流量 (单位:ml/min)
- temp: 透析液温度 (单位:℃)

医生口述:"今天给他做了2.5个超滤,流量调到200吧,温度保持36度"

请输出严格 JSON 格式,不要有其他文字:
{"uf": 2.5, "bf": 200, "temp": 36}

五、浏览器插件方案(方案 B)详解

5.1 插件核心功能

功能 说明
精准定位 通过 id 或 placeholder 匹配输入框(如”干体重”、”收缩压”)
自动填充 即使医生光标没点在框里,也能自动填入
格式校验 填入前检查数值是否在合理范围
高亮提醒 异常值在网页上给出高亮提示

5.2 插件配置要点

  • WebSocket 端口固定(如 127.0.0.1:9999)
  • manifest.json 配置正确的 content_security_policy
  • 处理 https 页面连接本地 ws 的跨域问题

5.3 DOM 填充示例

// 插件接收 JSON 后的填充逻辑
const fieldMapping = {
  'uf': ['超滤量', 'uf', 'ultrafiltration'],
  'bp_high': ['收缩压', 'systolic', 'bp_sys'],
  'bp_low': ['舒张压', 'diastolic', 'bp_dia'],
  'flow': ['透析流量', 'flow', 'blood_flow']
};

function fillForm(data) {
  for (const [key, selectors] of Object.entries(fieldMapping)) {
    if (data[key] !== undefined) {
      // 尝试多种选择器定位
      const input = document.querySelector(`input[placeholder*="${selectors[0]}"]`) 
                 || document.querySelector(`#${selectors[1]}`)
                 || document.querySelector(`[name="${selectors[2]}"]`);

      if (input) {
        input.value = data[key];
        input.dispatchEvent(new Event('input', { bubbles: true }));
      }
    }
  }
}

六、开发挑战与应对策略

6.1 全局热键冲突与权限

问题 对策
医生电脑预装输入法、医疗软件可能拦截快捷键 提供自定义快捷键功能
高权限 BS 系统页面全局热键可能失效 以管理员权限运行 Flutter 应用
常用快捷键被占用 默认使用不常用组合键(如 Ctrl+Shift+V)

6.2 多屏幕与 DPI 缩放

问题 对策
医疗环境多显示器配置常见 使用 screen_retriever 库获取精确屏幕参数
150% 缩放下悬浮窗位置偏移或模糊 使用逻辑像素,多分辨率适配测试

6.3 音频驱动与采集干扰

问题 对策
Windows 音频环境复杂(耳麦、扬声器混用) UI 上提供麦克风设备选择
采样率转换导致进程卡死 录音逻辑放在独立 Isolate 中,防止阻塞主线程
医生无法判断录音是否生效 显示音量波动条

6.4 浏览器插件跨域安全限制

问题 对策
Chrome/Edge 禁止连接不安全 WebSocket WebSocket 端口固定(如 9999)
https 页面连接本地 ws 被拦截 插件 manifest 配置 CSP,或使用 Native Messaging

6.5 资源占用与性能平衡

问题 对策
复杂动效导致内存飙升 200MB+ 使用 –release 编译,清理不必要资源
后台运行时资源浪费 不录音时窗口 Hide 而非 Close,降低心跳频率

6.6 FunASR 与 LLM 流式延迟

问题 对策
医生对等待敏感(录音5秒 + 处理3秒) FunASR 流式识别边说边出
整体延迟影响体验 ASR 识别出一半时预启动 LLM Prompt 准备

6.7 发布与分发(.dll 依赖)

问题 对策
Flutter Windows 编译后一堆 .dll 文件 使用 Inno Setup 打包成单一安装包
医生电脑缺少 VC++ 运行库 Inno Setup 中打包 Visual C++ Redistributable

七、UI 设计建议

7.1 悬浮预览窗

医生说完后,Flutter 弹出半透明浮窗显示识别结果:

┌─────────────────────────────┐
│  识别结果:超滤 2.5kg,血压 130/80  │
│                             │
│  [ ✓ 确认填入 (Enter) ]    │
│  [ ✕ 重说 ]                │
└─────────────────────────────┘

7.2 状态指示

  • 闲置状态:悬浮球灰色半透明
  • 录音中:悬浮球红色 + 音量波动
  • 处理中:悬浮球黄色旋转
  • 完成/错误:绿色勾或红色叹号

八、实施建议

8.1 MVP 路径

第一阶段:最小可行产品

  1. 实现”按住热键录音 → FunASR 转写 → 文字模拟输入到光标处”
  2. 验证闭环在透析系统环境下的权限隔离和热键响应

第二阶段:结构化填充

  1. 加入 Kimi/Minimax LLM 提取 JSON
  2. 实现浏览器插件 DOM 填充
  3. 增加”确认环节”防止填错

第三阶段:生产就绪

  1. 私有化 FunASR 部署
  2. 优化延迟和体验
  3. Inno Setup 打包分发

8.2 预计开发周期

阶段 内容 时间
MVP 热键 + 录音 + FunASR 转写 3 天
V1.0 + LLM 提取 + 文字填入 3 天
V1.1 + 浏览器插件 DOM 填充 5 天
V2.0 优化 + 私有化部署 + 打包 7 天
总计 18 天

九、需要生成的内容

如需要,可以进一步生成以下内容:

  1. Flutter 与浏览器插件通信 Demo 代码 - 验证 WebSocket 链路可行性
  2. Inno Setup 打包脚本模板 - 确保分发不报错
  3. FunASR API 封装示例 - 本地/内网部署参考
  4. 完整项目脚手架 - 从零开始的项目结构

整理备注

本文档基于群聊讨论整理,包含了 Flutter + FunASR + LLM 的完整技术方案、开发挑战与应对策略,以及分阶段实施建议。