测量员App-平曲线-交点法参数识别
把「直曲表」图片一键转化为结构化数据库,并进一步导出为「测量员 App」可直接读取的 CSV。两条识别流水线共用同一套冻结的表结构。
> 本技能为自包含技能包:所有脚本已打包在技能目录的 assets/ 下,路径均已改为相对/可配置,可在任意安装本技能的机器上运行(无需与本机目录一致)。
⛔ 调用纪律(最高优先级,覆盖一切下方说明)
- 本技能被触发且用户消息带直曲表图片时,唯一确定动作序列是:
1. 直接运行python assets/textin_pipeline.py <图片1> [图片2 ...](无需--out,默认落assets/workbench/runs/hcurve_<时间戳>,并固定复制一份到assets/workbench/runs/latest/)。
2. 运行结束后用present_files挂出assets/workbench/runs/latest/的三个 CSV(merged_curves.csv/merged_curves_main.csv/merged_curves_surveyor.csv),可一并挂report.md。 - 严禁发散:不做跨会话/跨任务归因分析、不对比历史结果、不推测连接器/额度/图质等外部因素、不反问用户选方案、不写多余解释。有图即跑、出文件即止。
- 严禁主动发散到工作台/网页/其他流水线,除非用户显式说「启动工作台」。
- 历史对话与之前任务效果一律不纳入本次执行判断;每次执行都是独立、确定的「图片 → 核心代码 → 文件」。
🚀 默认启动行为(用户选中本技能后,最简交互)
> 硬性前提:必须已在 WorkBuddy 中启动(连接/授权)TextIn 连接器。
> 技能以 --profile workbuddy --api auto 调用云端识别,连接器未连接时脚本会直接退出并报错,不会静默降级、也不会改用 OCR 本地流水线替代。请选择技能前先确认左侧「连接器」面板里 TextIn 状态为「已连接 / 已启用」。
- 触发:用户在 WorkBuddy 输入框拖入直曲表照片/图片并发送(可单张或多张)即自动执行「一键识别」,无需启动网页:
1. 从用户消息附件取得图片的本地路径(多张即多个路径)。
2. 运行(解释器用运行该脚本的 Python 3,仅需标准库即可;xparse 走 TextIn 云端,按 xparse 技能默认--api auto免费优先):
bash python <技能目录>/assets/textin_pipeline.py <图片1> [图片2 ...] --out <输出目录>- 前置门禁:脚本运行前会自动检查 TextIn 连接器是否已启动(
xparse-cli --profile workbuddy quota的authenticated状态)。若未启动/未授权,脚本立即退出(退出码 2)并输出「❌ 未检测到已启动的 TextIn 连接器……请启动」+ 启动步骤。此时 agent 应原样把这段提示转达给用户,不要继续识别、也不要静默改用 OCR。 - 通过后,脚本内部按约定顺序执行:xparse-cli 云端解析 →
textin_to_db落库(原始、空值保留)→merge_dbs按交点桩号最大化合并(附source_image溯源)→finalize_chainages处理特殊空值 → 生成三个 CSV + Markdown 报告(打印到 stdout 并写入report.md)。合并全表 CSV 已含全部 31 列要素 + 溯源列,无需再给库文件。 - 若用户已自行用 xparse 解析好 JSON,可改传
--jsons a.json b.json跳过大云端解析步骤。
3. 把脚本打印的 Markdown 报告直接展示在对话里,含三块:合并结果表(中文表头,含数据来源图)、主要参数表(11 列)、测量员App格式 CSV 预览。
4. ⚠️ 必须调用present_files把三个文件挂出(此步不可省略):识别报告文本打印 ≠ 交付完成。无论报告是否已显示,都必须在最后用present_files把三个文件卡片交给用户。文件固定副本位于<技能目录>/assets/workbench/runs/latest/(脚本另写一份带时间戳的到--out目录),present_files直接传该 latest 目录的三个 CSV 即可,也可同时传report.md。 merged_curves.csv(合并全表,UTF-8-BOM,含「数据来源图」溯源列)merged_curves_main.csv(主要参数 11 列,UTF-8-BOM)merged_curves_surveyor.csv(测量员App 格式 CSV,UTF-8-BOM,逗号分隔)
- 前置门禁:脚本运行前会自动检查 TextIn 连接器是否已启动(
- 若消息未带图片:提示用户「把直曲表照片拖进输入框发送即可」,不要自动启动网页。
- 若脚本因连接器未启动而退出:直接把脚本输出的「请启动 TextIn 连接器」提示(含启动步骤)转述给用户,并停止;不要尝试用 OCR 或其他方式绕过。
- 可视化网页(Streamlit 工作台)作为备选:说「启动工作台」即按下方说明拉起(注意:本沙箱内后台进程空闲几分钟会被回收,真·常驻见 README「常驻运行」节)。
> 输出目录建议:<技能目录>/assets/workbench/runs/hcurve_<时间戳>,便于回看与复下载。
⚠️ 最高优先级约定:表结构冻结
- 平曲线参数表的输出列集已确认锁定,后续识别【绝不】因图片表头差异(不同设计公司、字段不全、列序不同)而增删或重排列。
- 新表头 / 缺失列一律映射到下方固定字段,缺失即留空(None)。
- 若确需扩展字段,必须由用户显式确认,不得由识别代码自行决定。
- per-image DB 表(
horizontal_curves_auto/horizontal_curves)固定 33 个曲线要素列(不含内部自增id);merged_curves在此基础上追加source_image溯源列(仅溯源,非曲线要素)。 import_curve_data.py的SCHEMA常量是含project_name/drawing_no/created_at的 36 列超集参考,识别阶段不填充前两者。
何时用哪条流水线
- 追求精度 / 有网 / 省时 → TextIn 云端:
xparse-cli parse+textin_to_db.py。核心曲线要素一致率 ~99.1%,端到端 ~3.3s;对「主点桩号左移一格 / 非对称缓和曲线 / 串列」等病态排版更稳健。 - 离线 / 无 TextIn 连接器 / 需要右侧 4 列 → PaddleOCR 本地:
recognize_curve_table.py。核心一致率 ~84.6%,冷启动 ~60s(热缓存 <1s);弱点:转向(Y)/(Z)标记丢失、T/L 合并未拆、JD1 主点左移、非对称 Ls 误读。 - 两条流水线代码只增强不重写,保持并存。
流水线执行顺序(严格遵循)
先图形识别 → 再去重合并 → 最后处理特殊空值。
- 识别阶段只产出原始记录(空值保持 None),不提前置 0、不打"未识别"标记。
- 合并阶段:对 N 个有效 DB 调
merge_lib.merge_dbs(合并键 = 交点桩号jd_chainage,工程中严格递增唯一)。重复交点(如 JD15 跨页重复)做字段级最大化并集:互补列取并集、同列同值取其一、同列异值取最完整者并标记remarks冲突待复核。合并后按桩号升序即得真实交点序列(BP, JD1…JDn, EP)。 - 空值处理阶段:合并后对每条记录调用
import_curve_data.finalize_chainages,规则:
- R 有值而 Ls1/Ls2/A1/A2 全空且非 BP/EP → 判定圆曲线(无缓和曲线),置 Ls1=Ls2=A1=A2=0,备注"圆曲线(无缓和曲线)…可能为 OCR 漏读建议复核"。
- 非端点且 R 为 None → 备注半径缺失。
- ZH 空 → 取 HY/圆曲线起点桩号;HZ 空 → 取 YH/圆曲线终点桩号(Ls=0 回退)。
- 单图也必经merge_dbs收尾,保证必走 finalize。
主要参数表(11 列)
从完整 33 列中挑选的测量员 App 关注字段(对应导出 CSV 第 2…15 列,第 1 列为内部 id):
jd_no(交点号), point_type(点位类型), n_x(坐标N/X), e_y(坐标E/Y), jd_chainage(交点桩号), jd_chainage_m(交点桩号·米), radius_r(半径R), spiral_length_ls1(Ls1), spiral_length_ls2(Ls2), spiral_param_a1(A1), spiral_param_a2(A2)
工作台「主要参数表(测量员App用,11列)」展开区专门展示此子集,并提供「下载主要参数 CSV(11列)」。
测量员 App 格式导出(关键交付物)
函数 build_surveyor_csv(rows)(工作台 render_surveyor 调用),纯位置驱动,不依赖 point_type 标签:
- 第 1 行(起点) = 表第一行(无论标签),格式:
<起点桩号(数字)>,<起点X>,<起点Y> - 第 2…行(交点) = 中间所有行
rows[1:-1],按桩号升序,格式:<交点号>,<X>,<Y>,<Ls1>,<Ls2>,<A1>,<A2>,<R> - 字段顺序严格为 Ls1, Ls2, A1, A2, R(先长度后参数)
- 末行(终点) = 表最后一行(无论标签),格式:
<终点X>,<终点Y> - 逗号分隔、扩展名
.csv、UTF-8-BOM(Excel 友好)。 - 数值统一 3 位小数去尾零(如
40.0→40、34.641保留),空值输出空字段。
位置规则(重要):
- 起点 BP 只可能是表首行;若首行标签非 BP,按起点处理并告警"首行非BP标签,已按起点(BP)处理"。
- 终点 EP 只可能是表末行;若末行标签非 EP,按终点处理并告警。
- 中间即使出现 BP/EP 标签,也一律当 JD 处理并原样输出其交点号(如 BP2,… / EP2,…)。
- 旧兜底(无 EP 取末行 / 无 BP 跳过)已删除,因为首末行恒成立。
环境与路径(本技能包自包含)
- 所有脚本已打包在本技能目录的
assets/下,结构为assets/{import_curve_data.py, recognize_curve_table.py, textin_to_db.py, textin_pipeline.py, horizontal_curve.db, workbench/{app.py, merge_lib.py, launch.sh}}。 - Python(含 paddleocr、streamlit):默认取运行 app.py 的解释器;也可通过环境变量
PYTHON_BIN指定(例如指向含 paddleocr 的 venv)。 - TextIn CLI(
xparse-cli):默认从PATH查找;也可通过环境变量XPARSE_CLI指定绝对路径(需 WorkBuddy 已连接 TextIn xParse 连接器且账号可用)。 - 关键脚本(均在
assets/内):textin_pipeline.py(默认一键入口:照片→云端识别→合并→三文件(CSV)+报告,不输出 .db)、recognize_curve_table.py(OCR)、textin_to_db.py(TextIn 落库)、import_curve_data.py(含 SCHEMA 与 finalize_chainages)、merge_lib.py(merge_dbs 合并)、workbench/app.py(Streamlit 工作台)、workbench/launch.sh(一键启动网页)。
工作流
- 确认输入:拿到直曲表图片(如
路线2/ZQ1.png,可多张)。 - 默认·一键出表 + 三文件(推荐,无需网页):见上方「🚀 默认启动行为」。核心命令:
bash python assets/textin_pipeline.py <图片1> [图片2 ...] --out <输出目录>
脚本自动完成「云端解析 → 落库 → 合并 → 三个 CSV 文件 + 报告」,并把合并结果表、11 列主参数表、测量员 CSV 预览打印出来(不输出 .db)。 - 引擎对照(脚本内部已封装,一般不必手动拆):
- TextIn(默认):textin_pipeline.py内部调用xparse-cli parse --profile workbuddy --api auto --view json,再textin_to_db.py。
- OCR 本地(离线时用):python assets/recognize_curve_table.py <图片> --db out.db --report out.md --golden assets/horizontal_curve.db(注意:屏摄照片易令 OCR 列中心推导失败崩溃,见已知坑)。
- 多图合并:textin_pipeline.py接收多张图即自动merge_dbs合并;也可将多个 DB 直接传merge_lib.merge_dbs。 - 面向同事的可视化网页(备选):
bash assets/workbench/launch.sh启动 Streamlit 工作台(http://localhost:8501),拖图即识别、合并、预览并下载。
工作台(workbench/app.py)当前能力
- 图片拖拽上传(支持多张),逐图识别后
merge_dbs自动合并入库(最大化合并 +source_image溯源)。 - 三种模式:仅 PaddleOCR(本地)/ 仅 TextIn(云端,默认选中)/ 双流水线并排对比。
- 已移除与人工核验库对比:只做几何自洽校验与结果预览(旧
compare()/compare_golden死代码已清理)。 - 结果区中文表头;指标数值(图片数/合并交点数/几何异常/总耗时)字体缩至约一半;「逐图识别明细」置于「查看合并结果表」上方。
- 每个结果区三个下载按钮一行排列(
st.columns(3),顺序):识别/合并 CSV、主要参数 CSV(11列)、测量员 App 格式 CSV(不提供 SQLite 库下载,因合并全表 CSV 已含全部要素)。 - 识别成功以「DB 行数 > 0」判定;失败图显式 warning 横幅列出,绝不静默丢弃。
已知坑(务必对齐,避免前后矛盾)
- 照片鲁棒性限制:当前流水线针对干净规则图/截图设计。手机/相机屏摄图(含 PDF 工具栏、签名、键盘、水印、透视变形、反光、摩尔纹)会令 OCR 流水线列中心推导失败直接崩溃(IndexError),裁剪后仍严重错位。建议尽量用原 PDF 导出/截图;若只能用照片,须先预处理(裁剪到表格主体、透视校正、去反光、缩放到约 2200px 宽)。
- TextIn 右侧 4 列缺口:直线段长/交点间距/计算方位角/备注在密集表中常被漏抽,属覆盖缺口而非识别错误(核验库同值),会拉低全字段一致率但核心曲线要素一致率不受影响。
- 16 图丢失 bug 已修复:曾因
textin_to_db.py在另一路线(无交点号匹配 route1)时total=0触发ZeroDivisionError,且工作台以退出码判成功而静默丢弃 13 张。已加total==0守卫 + 工作台改以行数>0 判成功 + 失败图显式 warning,现 16 图→221 行正常。 - 圆曲线误标:JD2/3/4/7 这类"R 有值、Ls/A 全空"在 finalize 后置 0 并备注"可能为 OCR 漏读建议复核",需人工核对是否真圆曲线。
- 交付一致性(跨会话必读):识别结果文本(脚本 stdout 打印的合并表 / 主参数表 / CSV 预览)与「挂出可下载文件」是两道独立动作。
Skill工具只加载本说明、不会自动执行脚本、也不会自动挂文件;present_files必须由你在跑完脚本后显式调用。漏掉present_files会导致用户「看到表格却下不到文件」——这正是跨会话「效果差异」最常见的根因,务必在执行清单末尾确认已调用。脚本已把文件固定复制一份到<技能目录>/assets/workbench/runs/latest/,即使对话未挂出,用户也可直接打开该目录取用。
输出约定
- OCR 表名
horizontal_curves_auto,TextIn 表名horizontal_curves,合并表名merged_curves(含source_image)。 - 每次产物建议带时间戳或单独目录,避免覆盖
horizontal_curve.db(其为对比基准/核验库,不要当作待识别输入覆盖)。
安装与分发(技能包)
本技能目录本身即为可分发技能包,整目录复制即可在另一台机器的 WorkBuddy 中启用:
- 安装到用户级(所有项目可用):
将整个测量员App-平曲线-交点法参数识别/目录复制到~/.workbuddy/skills/。 - 安装到项目级(仅当前项目可用):
复制到<项目>/.workbuddy/skills/。 - 依赖准备(每台机器一次):
- Python venv 并安装:pip install paddleocr streamlit(OCR 与工作台需要)。
- 测量员 App 格式导出纯 Python,无需额外依赖。
- TextIn 云端引擎:需在 WorkBuddy 连接 TextIn xParse 连接器并取得可用额度;或设置环境变量XPARSE_CLI指向xparse-cli可执行文件。 - 可选环境变量(仅在非默认布局时设置):
-PYTHON_BIN:指定运行脚本/工作台的 Python 解释器(默认用运行 app.py 的解释器)。
-XPARSE_CLI:指定xparse-cli绝对路径(默认从 PATH 查找)。
-PYTHON_VENV:供launch.sh探测 venv(默认$HOME/.workbuddy/binaries/python/envs/road_ocr)。
-PORT:launch.sh启动的 Streamlit 端口(默认 8501)。
> 注意:技能包内的 assets/ 脚本为导出时点的快照。若后续在主工程中迭代了识别逻辑,请重新导出(重新复制 assets/ 并打补丁)以保持一致。