[开源] 科研样本外送检测全链路追踪系统:面向科研协调与检验管理的五节点时间轴工具
本项目是专为科研样本外送检测流程设计的轻量级全链路追踪系统,覆盖「申请→寄出→送达→检测→结果返回」五个确定性状态节点,服务于科研协调员、检验科管理员及科研处负责人三类核心角色。我们不替代LIMS或HIS,而是补足其在跨机构样本流转中缺失的时间轴显性化、PDF结果结构化、超时响应自动化三个关键断点。系统以CSV双通道采集(申请单+快递单)为起点,用LLM驱动PDF字段提取为终点,输出Web页面、CSV台账和CLI交互三种形态;技术栈采用Python 3.11+、SQLite本地持久化、FastAPI提供Web服务,并通过OpenAI/Anthropic API完成检测报告PDF的语义解析。
定位与能力边界
我们明确不做三件事:不接入物流厂商实时API(依赖人工导入快递单CSV),不对接医院内部检验仪器(仅处理已生成的PDF结果文件),不承担样本质量判定(所有状态变更由人工确认或规则触发)。
真正做好的只有一件事:把原本散落在邮件、微信、Excel、PDF里的五段关键时间,锚定到一个唯一sample_id下,形成可排序、可筛选、可告警、可导出的时间轴事实库。
这个“事实库”不是抽象概念,它直接对应数据库里一张表,每一行是一个样本,每一列是一个时间戳或结构化字段(如apply_time、result_pdf_url),所有Web页面、CLI命令、CSV导出都读写这张表。没有中间缓存,没有异步队列,SQLite就是单一真相源。
核心功能:五节点状态机与三重数据注入
系统围绕“五节点状态机”构建主干逻辑:applied → in_transit → received → testing → reported。每个状态有明确定义和进入条件,例如in_transit必须填写leave_time,received必须填写return_time,而reported则依赖PDF解析成功并填入至少一个检测字段。
这五个状态不是静态标签,而是驱动后续动作的开关。比如当状态为testing且return_time距今超48小时未更新result_received_time,即触发超时告警;当状态为received且上传了PDF,则自动调用LLM解析接口提取字段。
数据注入共三条通路,互不干扰又可叠加:
通路类型 | 输入形式 | 自动化程度 | 典型使用者 |
|---|---|---|---|
CSV申请单导入 | data/demo_samples.csv含 | 全自动解析+入库 | 科研协调员批量建样 |
快递单CSV关联 | 同一 | 自动匹配+时间戳填充 | 检验科管理员补寄送信息 |
PDF结果上传 | 上传检测报告PDF,点击「关联PDF」按钮 | LLM自动提取 | 科研处负责人归档结果 |
注意:三条通路均不修改原始文件,所有解析结果写入SQLite,原始CSV和PDF保留在本地路径供审计回溯。
超时告警规则:用DSL定义催办逻辑
我们不预设“检测应在5个工作日内完成”这类刚性规则,而是提供一套轻量DSL(领域特定语言),让管理员按需配置。规则写在config/alert_rules.yaml中,示例:
- name: "寄出超时" condition: "status == 'applied' and (now() - apply_time).hours > 24" action: "send_wechat('请尽快寄出样本S{sample_id}')" - name: "结果滞留" condition: "status == 'received' and (now() - return_time).hours > 48" action: "escalate_to('检验科主任')"每条规则含三部分:名称(仅用于日志)、condition(基于当前样本字段和内置函数的布尔表达式)、action(触发通知或升级动作)。所有规则在CLI执行check-alerts或Web页面刷新时实时求值,不依赖定时任务。DSL语法严格限制在安全子集内,无法执行任意代码,保障运行时隔离。
使用与配置:从零启动只需三步
你不需要部署服务器、不需配置Nginx、不需申请API密钥(默认使用免费层配额)。只要本地有Python 3.11环境,三步即可跑通全流程:
第一步:安装依赖
pip install -r requirements.txt第二步:初始化示例数据(自动创建SQLite并导入demo)
python -m src.data.csv_parser data/demo_samples.csv第三步:启动Web服务(开发模式,带热重载)
uvicorn src.output.web:app --reload --port 8000启动后访问 http://127.0.0.1:8000/samples,即可看到带时间轴卡片的样本列表页。每个卡片显示sample_id、当前状态色块、各节点时间戳(空值显示“待填写”)、操作按钮(关联PDF、编辑、标记完成)。
CLI作为补充界面,适合批量操作与脚本集成:
-python -m src.output.cli add:交互式录入新样本(提示输入sample_id,apply_time等)
-python -m src.output.cli list --status testing:按状态过滤列出所有检测中样本
-python -m src.output.cli view S20260516001:打印该样本完整时间轴与PDF提取字段
-python -m src.output.cli check-alerts:运行全部告警规则并输出触发项
所有CLI命令均支持--help查看参数说明。
数据字段与业务含义对齐
系统暴露的每个字段都对应真实业务动作,无冗余、无抽象建模。我们坚持“字段即动作”,例如:
字段名 | 业务含义 | 填写时机 | 是否可为空 |
|---|---|---|---|
sample_id | 样本唯一编号,由科研协调员在申请时生成 | 录入首步必填 | 否 |
apply_time | 科研人员提交送检申请的时间点 | CSV导入或CLI录入时填写 | 否 |
leave_time | 样本实际交寄快递的时间(非面单打印时间) | 快递单CSV导入或Web手动编辑 | 状态为 |
return_time | 检测机构签收样本的时间(以快递物流记录为准) | 快递单CSV导入或Web手动编辑 | 状态为 |
result_received_time | 科研方收到PDF检测报告的时间 | 上传PDF后自动填充(或手动补) | 状态为 |
result_pdf_url | PDF文件本地路径或HTTP链接 | Web上传后自动生成 | 状态为 |
linked_apply_id | 关联的原始申请单号(如OA流水号) | 可选,用于跨系统追溯 | 是 |
status | 当前所处状态节点,仅限五值之一 | 由时间戳填写自动推导或手动切换 | 否 |
特别说明:status不是独立维护字段,而是由各时间戳存在与否自动计算得出。例如当apply_time存在但leave_time为空,状态即为applied;当leave_time和return_time均存在但result_received_time为空,状态即为received。这种设计避免状态与时间戳人为不一致。
工程结构:模块职责清晰,扩展成本可控
整个项目按能力切分为六个主模块,每个目录对应单一职责,无交叉引用:
目录路径 | 职责说明 | 典型文件 |
|---|---|---|
src/data/ | 数据解析与入库:CSV读取、字段校验、SQLite写入 | csv_parser.py, |
src/llm/ | PDF语义解析:调用大模型API、定义prompt模板、清洗提取结果 | pdf_extractor.py, |
src/rules/ | 告警规则引擎:DSL解析器、条件求值器、动作执行器 | dsl_parser.py, |
src/output/web/ | Web界面:FastAPI路由、Jinja2模板、状态渲染逻辑 | main.py, |
src/output/cli/ | 命令行界面:Argparse参数定义、交互逻辑、输出格式化 | __main__.py, |
src/utils/ | 通用工具:时间格式转换、ID生成、日志封装 | time_utils.py, |
新增一种数据源(如对接某快递API)只需在src/data/下新增一个解析器类,不改动其他模块;更换LLM供应商只需修改src/llm/pdf_extractor.py中的客户端初始化逻辑。所有模块通过src/__init__.py统一暴露接口,无隐式依赖。
限制与说明
本系统当前版本明确存在以下限制,均已在设计阶段权衡取舍:
-PDF解析依赖网络API:需自行配置OpenAI或Anthropic密钥(写入.env),离线不可用;但解析失败不影响时间轴主体功能,仅PDF字段为空。
-SQLite单机存储:不支持多用户并发写入,适用于单人管理或小团队共享一台电脑的场景;若需协同,建议通过Git同步SQLite文件(二进制diff友好)。
-中文PDF支持有限:LLM prompt针对中英文混合检测报告优化,纯中文PDF(尤其表格密集型)可能漏提字段;建议优先使用带标准字段命名的PDF模板。
-无用户权限体系:Web界面默认开放读写,生产环境如需多角色控制,需在Nginx层加基础认证,或自行扩展FastAPI的Auth中间件。
这些限制不是缺陷,而是我们为保持轻量、可审计、易迁移所做的主动选择。如果你的场景需要集群部署、RBAC或OCR本地化,欢迎提交Issue讨论演进路径。
项目地址:
https://github.com/nexorin9/research-sample-timeline-tracker
