给谁看: 要手工把 data\raw 下的原始数据算成系统能显示的东西的人。
前提: 已经跑过 install.bat(有 .venv)、.venv\Scripts\python.exe 存在。
所有命令都在安装根目录下敲(F:\temp\guanlan-rudong-v2_0.2.0\) —— 脚本按自身位置解析路径, 但相对路径参数
(如 --src)会按当前目录解释, 站在根目录最省事。
一句话原理: 页面的数来自
outputs\rudong\里的产物; 产物由data\raw\下的原始件算出来;data\raw\的下一级目录名就是场站名称(扫描辨识, 不写死)。所以流程永远是: 放数据 → 算 → 重启服务 → 看页面。
scripts/rebuild_all.py, 2026-09-12)前面那些步骤已经串成一个入口 —— 依赖顺序、验收锚点、子进程编码都写死在脚本里, 不用记顺序:
cd /d <安装目录>
:: 全套 (含 SCADA 侧 10 个构建器, 逐台读 ~14 GB, 约 15 分钟)
.venv\Scripts\python.exe scripts\rebuild_all.py
:: 常用档: 只换了台账类数据, 没动 scada_10min
.venv\Scripts\python.exe scripts\rebuild_all.py --skip-scada
:: 连"放数据"一起 (现场包目录)
.venv\Scripts\python.exe scripts\rebuild_all.py --src F:\temp\如东风场数据
:: 其它开关
.venv\Scripts\python.exe scripts\rebuild_all.py --dry-run :: 只打印计划, 不执行
.venv\Scripts\python.exe scripts\rebuild_all.py --no-restart :: 不碰服务(自己管启停)
.venv\Scripts\python.exe scripts\rebuild_all.py --with-verify :: 末尾加台账等价验收(需随包基线在位)
它按什么顺序做(为什么是这个顺序见脚本头部注释):
| 步 | 做什么 | 脚本 |
|---|---|---|
| ① | 放数据(给了 --src 才跑) |
place_raw_data.py --scope full |
| ② | 三门台账(报警/工单/油样) | rebuild_from_raw.py |
| ③ | SCADA 侧 10 个构建器 | rebuild_from_raw.py --scada |
| ④ | 月度派生件 | windscada_monthly_build.py |
| ⑤ | 补齐"包内没有生成端"的产物 | products_restore_missing.py |
| ⑥ | 重启服务(必须: ⑦ 要吃 /api/fleet) |
guanlan.py stop / serve |
| ⑦ | 本体层: 码表→铺开→决策链→趋势→检索→参数表 | -m src.ontology.* |
| ⑧ | 本体审计 + (可选)等价验收 | -m src.ontology.audit 等 |
每步都是幂等的, 中途失败就按日志处理完再重跑同一条命令; 某步失败会立刻停下(后续步骤依赖它),
最后打印每步的 OK/FAIL 与耗时。
手工分步执行的完整版在 §1~§5b(换现场包、单跑某一环、或想知道每一步期望输出时看那些)。
.venv\Scripts\python.exe scripts\scan_stations.py :: 系统认到哪个场站、四类源各多少件、有没有"缺"
.venv\Scripts\python.exe scripts\rebuild_from_raw.py --dry-run :: 重算会做哪几步(不写盘)
.venv\Scripts\python.exe scripts\products_state.py --status :: 产物在位还是被挪走
scan_stations.py 的期望输出(当前这台机器):
扫描到 1 个场站目录:
如东 (631 件) ...\data\raw\如东 ← 就绪
scada_10min 38 件
scada_1min 38 件
故障报警 16 件
风机故障记录 135 件
油样报告 404 件
辨识结论 : how=raw_station ← 目录名与场配置 raw_station 完全相同
http://127.0.0.1:28084/ops, 2026-09-12)不想敲命令就用它 —— 一件事一个按钮, 按钮的可用/不可用是按真实状态判的(不是样子货):
| 按钮 | 什么时候可用 | 点了做什么 |
|---|---|---|
| 启动服务(并打开门户) | 有组件服务未运行 | guanlan.py serve, 等门户就绪后自动打开 http://127.0.0.1:28084/ |
| 停止组件服务(保留控制台) | 有组件服务在运行 | 只停 detail/cms/sim/sim_sys/viewer —— 保留网关, 否则按钮点完页面就没了 |
| 完整重启(含网关) | 有组件服务在运行 | 分离进程先停再起; 页面断开约 15 s 后自动恢复 |
| 执行重算 | 没有任务在跑 | rebuild_all.py(默认跳过 SCADA; 可勾选含 SCADA / 末尾加等价验收) |
| 恢复产物 | 产物被清空过 | products_state.py --on(恢复后请点"启动服务") |
| 清除产物(可恢复) | 产物在位 且 没有任务在跑 | products_state.py --off, 暂存区有同名产物时自动加 --archive-old |
页面还实时显示: 各服务端口通不通 · 产物件数与分仓 · 来源台账(raw 重算多少件 / 随包补齐多少件) · 验收锚点(报警 39211 行 · 工单 5876 · temp_monthly 19494 · 本体 9702 对象) · 最近一次动作的状态、 退出码、耗时与日志尾巴(边跑边刷新, 2 s 一次)。
三条纪律(写在后端, 前端禁用只是提示 —— 直接打 API 也会被拒):
409 已有任务在跑 (…)。409 组件服务都在运行, 无需启动;
组件都停了点"停止"→ 409 组件服务都已停止, 没有可停的; 产物已清空再点"清除"→ 409 …无需再清。实现: 页面与 API 在 scripts/guanlan_ops.py(网关只做转发); 动作由 scripts/_ops_run.py 执行
(把真实退出码写回 run/ops_job.json, 页面据此显示"完成(退出码 0)"或失败); 日志在 logs/ops_<动作>_<时间>.log。
现场给的通常是几个 GBK 名的大压缩包。不要手工拖拽, 用映射表脚本落位(可复核、可反复跑):
:: 先看要落什么
.venv\Scripts\python.exe scripts\place_raw_data.py --src F:\temp\如东风场数据 --scope full --dry-run
:: 真落位
.venv\Scripts\python.exe scripts\place_raw_data.py --src F:\temp\如东风场数据 --scope full
| 范围 | 落什么 |
|---|---|
--scope a2 |
四项数据层: scada_10min / 故障报警 / 风机故障记录 / 油样报告 |
--scope mech |
机理层源件 data\raw\西门子4.0技术资料\(含那份对译表) + <场站>\scada_1min\ |
--scope full |
两组一起(从零重算要用的全集) |
同尺寸文件会自动跳过, 所以重复跑很便宜(不用怕重抄十几 GB)。--src 不给会去找 data\_incoming\(默认)。
configs\ 场配置里的 raw_station 一致(当前 如东)。scada_10min / scada_1min / 故障报警 / 风机故障记录 / 油样报告。scada_10min 必须是逐台平铺的 WTG01.csv…WTG38.csv 本身 —— 不能是压缩包、不能再套一层目录。data\raw\西门子4.0技术资料\(不在场站目录下)。:: ① 三门台账(报警/工单/油样): 秒级~分钟级
.venv\Scripts\python.exe scripts\rebuild_from_raw.py
:: ② SCADA 侧 10 个构建器(逐台读 38 个 ~380MB CSV, **约 15 分钟**, 建议放后台或别关窗口)
.venv\Scripts\python.exe scripts\rebuild_from_raw.py --scada
②跑的 10 步(顺序 = 依赖顺序): 功率曲线 → 可用率与损失 → 七镜头曲线 / 控制策略件 / 停机事件 → 温度 NBM / 偏航 / 液压蓄能 / 热链 / 系统辅助。
期望结果(本机实测):
| 产物 | 行数 |
|---|---|
alarms.parquet |
39,211 |
workorders.parquet |
5,876 |
oil_samples_index.parquet |
404(见 §7 的 102 行说明) |
loss_monthly.parquet |
3,729 |
temp_bins.parquet |
24,624 |
curve_lenses.parquet |
7,676 |
stop_events.parquet |
2,318 |
powercurve_bins.parquet |
912 |
curve_liveness / control_schedule |
304 |
yaw_daily / hydraulic_accum / thermal_chain / system_aux / control_profile / powercurve_dev |
各 38(逐台一行) |
没换 SCADA 数据就不用跑 ②(① 是吃台账表的, 现场按月给表时跑 ① 就够)。
rebuild_from_raw.py 只覆盖 16 件; 随包里另有 15 件 parquet 全库没有生成端, 而工作台主数据
/api/fleet / 单机页 / 振动融合页都依赖它们 —— 缺了就是"页面没数据"。两条路补齐:
:: ① 能从 raw 重算的: 月度派生件(逐值对齐随包件才落盘)
.venv\Scripts\python.exe scripts\windscada_monthly_build.py --verify :: 先看对齐情况
.venv\Scripts\python.exe scripts\windscada_monthly_build.py :: 算并写盘
:: ② 没有生成端、或规则未复现的: 从随包件补齐(只补缺件, 不动 raw 重算件), 并落来源台账
.venv\Scripts\python.exe scripts\products_restore_missing.py --dry-run
.venv\Scripts\python.exe scripts\products_restore_missing.py
② 会在 outputs\<场>\_provenance.json 写一份逐件来源台账:
raw-derived(由 data/raw 重算, 含验证依据) 与 shipped(包内无生成端, 用随包件补齐)。
任何人想知道"这一页的数是自己算的还是随包带的", 查这份台账即可。
已确认可重算的月度件: temp_monthly(每台×每月×每个温度通道, 在 发电态 p≥500kW 行上的中位数,
19494/19494 逐值一致 —— 口径出处 src/windscada/subsys/temp_nbm.py 的"发电态×功率档(500kW)")。
未复现、暂用随包件: pitch_daily(液压四列 hyd_mean/over_relief/under_pump 的规则试了
日界位移与越限穿越计数都对不上, 不猜)、pc_monthly_bins/duty_monthly/thermal_monthly/sector_power/
structure/watch_channels_monthly/control_monthly/yaw_*/genbearing_monthly/mblub_monthly。
:: 对象库(技术资料 + 故障处理手册 + 码表 + 工单/报警) → objects.json
.venv\Scripts\python.exe -m src.ontology.kb_ingest
:: 铺开: 38台×九系统判级 + 振动 handoff + 工单 + 油样 + 机制库 (需 ②的产物已在位)
.venv\Scripts\python.exe -m src.ontology.populate
.venv\Scripts\python.exe -m src.ontology.chain_ingest :: 决策链进度(需 windscada 服务在跑)
.venv\Scripts\python.exe -m src.ontology.trend_ingest :: 在升/闭环证据
:: 检索索引(BM25 词法索引; 向量那半要 Ollama 的 bge-m3, 本机没模型时会跳过, 纯词法仍可用)
.venv\Scripts\python.exe -c "from src.ontology import retrieval as R; R.build(use_vec=False)"
:: 实机参数表(1706 条整定值, 源件是技术资料里的 Turbine+Parameters.*.xlsx)
.venv\Scripts\python.exe -c "from src.ontology.maintenance import refresh_params as f; print(f())"
:: ★验收: 官方本体审计(悬空引用/孤岛对象/声明面=证据面), 期望 0 问题
.venv\Scripts\python.exe -m src.ontology.audit
期望: kb_ingest 打印 {'AlarmCode': 555, 'WorkInstruction': 559, 'FailureMode': 150, 'MaintTask': 559, 'Doc': 303, 'Component': 9, ...};
populate 打 2341 → 9669; 全链跑完 audit 报 9701 对象 / 0 问题(本机实测)。
--verify 拿随包基线逐键逐值比对重算件, 把差异分成"旧链已知缺陷 / 本链新增覆盖 / 无法归类"三类,
只有第三类才算不通过(退出码 4)。
基线不参与运行, 平时是单独存着的(_products_off\_baseline_kept\), 验收时临时放回:
:: ① 临时放回基线(3 件 1.1 MB)
xcopy /E /I /Y "_products_off\_baseline_kept\_pre_rebuild_20260911" "outputs\rudong\windscada\_pre_rebuild_20260911"
:: ② 验收(只比不算)
.venv\Scripts\python.exe scripts\rebuild_from_raw.py --verify
:: ③ 验完撤走, 让产物仓只留重算出来的东西
rmdir /S /Q "outputs\rudong\windscada\_pre_rebuild_20260911"
期望结论: alarms 39211/39211 逐值完全一致; workorders 8 行差异全部可归类(旧链的时间解析缺陷)
产物换了必须重启: CMS 等模块是启动时加载数据的, 不重启页面还是旧数; 反过来, 产物被挪走期间起的
那次 CMS 会直接崩(表现为 /cms/ 503)。
.venv\Scripts\python.exe guanlan.py stop
.venv\Scripts\python.exe guanlan.py serve
期望: 状态 degraded offline 模块 5/7 ok, 并列出 DOWN 的项。
:: ① 清掉 (整体挪走, 不是删除 —— 一条命令能还原)
.venv\Scripts\python.exe scripts\products_state.py --off --archive-old
:: 暂存区里已有上一代产物时**必须加 --archive-old**: 否则会被拦住(见下), 因为挪走的落点是
:: _products_off\<场>\<目录>, 那里已有同名目录时 shutil.move 会嵌套成 windscada\windscada\,
:: 之后 --on 就把两代混在一起还原。加了它 = 自动把上一代存档到 _products_off_prev_<时间戳>\
:: (随包基线 _baseline_kept\ 留在原地, rebuild_from_raw --verify 还要用)。
:: ② 重启服务 (产物没了必须重启, CMS 等是启动时加载数据)
.venv\Scripts\python.exe guanlan.py stop
.venv\Scripts\python.exe guanlan.py serve
:: ③ 看空状态: / 门户仍 200 (门户在 release\, 不是产物); /cms/ 变 503;
:: /detail/api/fleet 回 err=no_products; 维护页「数据层」各项 条数=0 / 存在=False
:: ④ 还原
.venv\Scripts\python.exe scripts\products_state.py --on
.venv\Scripts\python.exe guanlan.py stop ; .venv\Scripts\python.exe guanlan.py serve
不想用开关也行(整目录搬走, 最直观):
Move-Item outputs\rudong F:\temp\products_off_20260912 :: 清
.venv\Scripts\python.exe guanlan.py stop ; .venv\Scripts\python.exe guanlan.py serve
Move-Item F:\temp\products_off_20260912 outputs\rudong :: 还原
清的是
outputs\<场>\(产物仓), 不动data\raw\(现场数据)、release\(门户外壳与交付件)、logs\/run\(运行期)。所以清完门户首页照旧打开 —— 那是静态交付页, 本来就不读产物。
:: ① 放数据 (现场包 → 约定目录; 同尺寸自动跳过)
.venv\Scripts\python.exe scripts\place_raw_data.py --src F:\temp\如东风场数据 --scope full
:: ② 台账 + SCADA 侧 10 个构建器 (后者约 15 分钟)
.venv\Scripts\python.exe scripts\rebuild_from_raw.py
.venv\Scripts\python.exe scripts\rebuild_from_raw.py --scada
:: ③ 月度派生件 (能从 raw 重算的那批; --verify 先看与随包件逐值是否一致)
.venv\Scripts\python.exe scripts\windscada_monthly_build.py --verify
.venv\Scripts\python.exe scripts\windscada_monthly_build.py
:: ④ 本体层 (技术资料须已放好)
.venv\Scripts\python.exe -m src.ontology.kb_ingest
.venv\Scripts\python.exe -m src.ontology.populate
.venv\Scripts\python.exe -m src.ontology.chain_ingest :: 需 windscada 服务在跑
.venv\Scripts\python.exe -m src.ontology.trend_ingest
.venv\Scripts\python.exe -c "from src.ontology import retrieval as R; R.build(use_vec=False)"
.venv\Scripts\python.exe -c "from src.ontology.maintenance import refresh_params as f; print(f())"
.venv\Scripts\python.exe -m src.ontology.audit :: 期望 0 问题
:: ⑤ "包内没有生成端"的那批: 从随包件补齐(只补缺件, 不动上面重算出来的), 并写来源台账
.venv\Scripts\python.exe scripts\products_restore_missing.py --dry-run
.venv\Scripts\python.exe scripts\products_restore_missing.py
:: ⑥ 重启 + 核验
.venv\Scripts\python.exe guanlan.py stop ; .venv\Scripts\python.exe guanlan.py serve
.venv\Scripts\python.exe -m src.ontology.maintenance :: 数据层/机理层的条数与末次更新
只想要"能打开页面"的最小集: ② 的 rebuild_from_raw.py + ③ + ⑤ 三步即可
(⑤ 把没有生成端的件补上, 页面就有数); ① 只在换了现场包时需要。
验收锚点: outputs\rudong\windscada\alarms.parquet 39211 行 ·
temp_monthly.parquet 19494 行(与随包件逐值一致) · 本体 objects.json 9701 对象 / audit 0 问题 ·
_provenance.json 记着每件是 raw 重算还是随包补齐。
命令行(不开浏览器):
.venv\Scripts\python.exe -m src.ontology.maintenance :: 数据层+机理层逐行: 覆盖/条数/末次更新/摄入命令
.venv\Scripts\python.exe guanlan.py status :: 各服务端口与进程
.venv\Scripts\python.exe guanlan.py check :: 自检(依赖/产物/发布件/模型)
浏览器: http://127.0.0.1:28084/detail/ → 维护页「数据层 + 机理层」那两屏 ——
每行都写着它自己的摄入命令, 以后忘了敲什么直接看页面。
回归尺子(与出厂基线比对 10 个端点):
.venv\Scripts\python.exe scripts\page_fingerprint.py --save F:\temp\fp_now.json
.venv\Scripts\python.exe scripts\page_fingerprint.py --diff F:\temp\fp_before.json
| 现象 | 原因 | 怎么办 |
|---|---|---|
/cms/ 503 |
CMS 的源是振动线 handoff(测点索引), 现场包里只有成品牌报告 PDF | 找振动线要测点导出件 |
| `/detail/api/query | turbine | fleet回err=no_products` |
| 油样只有 404 行(出厂 506) | 差的那 102 行来自一份合并报告, 该 PDF 不在现场包里 | 把该批报告放进 油样报告\ 后重跑 ① |
门户没有"契约结论段"、/api/facts 503 |
契约要 sop\findings.json + paradigm_r1 底稿, 两者本身没有生成端 |
找研发要 |
populate / audit 退出 1 |
卡在 pitch\pitch_daily.parquet(变桨产物无生成端) |
同上 |
/local-ai/ 503 |
本机 Ollama 未运行或没有模型(环境项, 与数据无关) | ollama pull 见 configs\models.json |
products_state.py --on 会删掉重算产物。它按清单把随包产物挪回来, 且目标目录存在就先 rmtree
(scripts\products_state.py 第 110-112 行)。当前清单覆盖 outputs\rudong\{ontology, windscada, …} ——
也就是说: 想让"原始重算"的结果留着, 就不要跑 --on。要拿随包产物就先备份自己的重算结果。
只想取验收基线 → 用 §4 的 xcopy, 别用 --on。:: 现状
.venv\Scripts\python.exe scripts\scan_stations.py
:: 放数据(现场包还在 F:\temp\如东风场数据)
.venv\Scripts\python.exe scripts\place_raw_data.py --src F:\temp\如东风场数据 --scope full
:: 算
.venv\Scripts\python.exe scripts\rebuild_from_raw.py
.venv\Scripts\python.exe scripts\rebuild_from_raw.py --scada :: 约 15 分钟
.venv\Scripts\python.exe -m src.ontology.kb_ingest
:: 重启
.venv\Scripts\python.exe guanlan.py stop
.venv\Scripts\python.exe guanlan.py serve
:: 看
.venv\Scripts\python.exe -m src.ontology.maintenance
:: 浏览器 http://127.0.0.1:28084/detail/ → 维护页「数据层」
相关文档: docs\数据目录结构与落位约定_v0.2.md(§2 落位 · §4 重算边界表) ·
docs\重算缺口与补件清单_v0.1.md(缺什么找谁补) · _修复记录_20260911\README.md(踩过的坑)