重命名 refs 为 algorithm_subprocesses,并清理误提交的权重与缓存文件。

算法子进程目录仅保留源码与配置;权重、样本 I/O、构建产物通过 .gitignore 离线交付。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Kevin
2026-05-21 16:10:08 +08:00
parent 1af442481e
commit 70431ca3f9
19 changed files with 88 additions and 34 deletions

10
.gitignore vendored
View File

@@ -56,6 +56,16 @@ backend/Ultralytics/
# Large model weights (deploy via mount or offline delivery)
backend/app/resources/actionformer_epoch_045.pth.tar
# Algorithm subprocess bundles — runtime assets ignored via backend/algorithm_subprocesses/.gitignore
backend/algorithm_subprocesses/**/weights/*
!backend/algorithm_subprocesses/**/weights/.gitkeep
backend/algorithm_subprocesses/**/input/*
!backend/algorithm_subprocesses/**/input/.gitkeep
backend/algorithm_subprocesses/**/output/*
!backend/algorithm_subprocesses/**/output/.gitkeep
backend/algorithm_subprocesses/**/data/*
!backend/algorithm_subprocesses/**/data/.gitkeep
# --- Clients ---
clients/demo-client/.runtime/
clients/demo-client/labels.json

View File

@@ -10,6 +10,6 @@ __pycache__
.env.*
!.env.example
!.env.prod
refs
algorithm_subprocesses
*.md
.dockerignore

View File

@@ -0,0 +1,44 @@
# 算法子进程包algorithm subprocess bundles
# 源码与配置保留在 git权重、样本 I/O、构建缓存离线交付或挂载。
# 详见 algorithm_subprocesses/5.15/README.md §「准备权重与输入」。
# --- 运行时 I/O保留 .gitkeep---
**/weights/*
!**/weights/.gitkeep
**/input/*
!**/input/.gitkeep
**/output/*
!**/output/.gitkeep
**/data/*
!**/data/.gitkeep
# --- 大文件 / 离线资产 ---
*.pt
*.pth
*.pth.tar
*.pkl
*.task
*.mp4
*.xlsx
*.xls
**/商品信息表.xlsx
# --- 子包运行时 ---
doctor_identity_package/.mediapipe_models/
**/infer_single_*/input/
**/*_run.log
**/output/result.txt
# --- Python 构建与缓存(子进程内 pip install / 编译产物)---
**/__pycache__/
**/*.py[cod]
**/*$py.class
**/.pytest_cache/
**/.mypy_cache/
**/.ruff_cache/
**/.cache/
**/build/
**/*.egg-info/
**/*.so
**/*.o
**/dist/

View File

@@ -1,4 +1,4 @@
"""ActionFormer 实时段落检测 + 41 类耗材:使用 ``refs/5.15`` 源码,输入为 RTSP。"""
"""ActionFormer 实时段落检测 + 41 类耗材:使用 ``algorithm_subprocesses/5.15`` 源码,输入为 RTSP。"""
from app.algorithm_runner.actionformer_gated.runner import (
ActionFormerSegmentRecord,

View File

@@ -1,6 +1,6 @@
"""ActionFormer 加载与单视频 forward使用 refs/5.15 vendor 源码)。
"""ActionFormer 加载与单视频 forward使用 algorithm_subprocesses/5.15 vendor 源码)。
复刻 refs/5.15 ``run_haocai_actionformer_consumables_e2e`` 写出的 ``infer_single.yaml``
复刻 algorithm_subprocesses/5.15 ``run_haocai_actionformer_consumables_e2e`` 写出的 ``infer_single.yaml``
推理配置(``haocai_main_perspective_videoswin``input_dim=768, num_classes=1,
feat_stride=32, num_frames=64, max_seq_len=2304, fpn_type=identity,
n_mha_win_size=19, embd_dim=fpn_dim=head_dim=256, n_head=4, use_abs_pe=False。
@@ -35,7 +35,7 @@ def _make_inference_cfg(
feat_stride: int,
num_frames: int,
) -> dict:
"""refs/5.15 e2e ``write_infer_yaml`` 同语义的推理时 cfg dict。"""
"""algorithm_subprocesses/5.15 e2e ``write_infer_yaml`` 同语义的推理时 cfg dict。"""
cfg = deepcopy(load_default_config())
cfg["dataset_name"] = "thumos"

View File

@@ -1,6 +1,6 @@
"""Online ActionFormer 子进程算法核心。
refs/5.15 ``run_haocai_actionformer_consumables_e2e`` 的批处理流水线改造为可吃 RTSP
algorithm_subprocesses/5.15 ``run_haocai_actionformer_consumables_e2e`` 的批处理流水线改造为可吃 RTSP
的实时近似:
* 逐帧维护 64 帧(``CLIP_LEN * FRAME_STRIDE``)的 RGB 224x224 ring。
@@ -90,7 +90,7 @@ class _FrameClsState:
@dataclass
class _Feature:
"""特征缓冲单元:对应 refs/5.15 离线 ``feats[i]``。"""
"""特征缓冲单元:对应 algorithm_subprocesses/5.15 离线 ``feats[i]``。"""
t_center: float # 该 clip 中心对应的流时间(秒)
feat: np.ndarray # shape [INPUT_DIM] float32
@@ -175,7 +175,7 @@ def _to_segment_records(
class OnlineActionFormerRunner:
"""RTSP 实时版的 refs/5.15 流水线,公共 API 与 ``TearGatedSegmentRunner`` 同形。"""
"""RTSP 实时版的 algorithm_subprocesses/5.15 流水线,公共 API 与 ``TearGatedSegmentRunner`` 同形。"""
def __init__(
self,
@@ -404,7 +404,7 @@ class OnlineActionFormerRunner:
self._frame_ring_t.append(float(t_abs))
def _maybe_extract_videoswin_feature(self) -> None:
# 与 refs/5.15 离线对齐feature i 对应 clip 起始帧 s = i * feat_stride_frames
# 与 algorithm_subprocesses/5.15 离线对齐feature i 对应 clip 起始帧 s = i * feat_stride_frames
# clip 末尾帧 s + (clip_len - 1) * frame_stride。当 ring 已塞满clip_span
# 帧),且当前 frame_idx == s + clip_span - 1即 (frame_idx + 1) %
# feat_stride_frames == 0 且 frame_idx >= clip_span - 1即可产新特征。

View File

@@ -56,7 +56,7 @@ def haocai_softmax_probs(
*,
device: str | None = None,
) -> np.ndarray | None:
"""耗材分类:返回长度 n_cls 的 softmax 概率向量(与 refs/5.15 同语义)。"""
"""耗材分类:返回长度 n_cls 的 softmax 概率向量(与 algorithm_subprocesses/5.15 同语义)。"""
if crop.size == 0:
return None
r = cls_model.predict(crop, imgsz=imgsz, verbose=False, device=device)[0]

View File

@@ -1,4 +1,4 @@
"""VideoSwin (Swin3D-T, Kinetics-400) feature extractor backed by refs/5.15.
"""VideoSwin (Swin3D-T, Kinetics-400) feature extractor backed by algorithm_subprocesses/5.15.
The online runner keeps a small wrapper API, but model construction and clip
preprocessing are delegated to the configured reference bundle's
@@ -50,7 +50,7 @@ class VideoSwinFeatureExtractor:
"""Thin wrapper over swin3d_t + preprocess_clip.
输入:``frames_rgb`` 为 32 帧(``CLIP_LEN``RGB 帧(``np.ndarray[H, W, 3]``)。
输出:``[INPUT_DIM]`` 一维特征张量CPUrefs/5.15 离线提特征同语义。
输出:``[INPUT_DIM]`` 一维特征张量CPUalgorithm_subprocesses/5.15 离线提特征同语义。
"""
def __init__(self, *, device: torch.device, image_size: int = 224) -> None:

View File

@@ -1,6 +1,6 @@
"""子进程入口:读 RTSP + 白名单 JSON段级结果追加写入 JSONL。
基于 refs/5.15 ``actionformer_gated`` 流水线VideoSwin → ActionFormer + 手检/好坏帧/
基于 algorithm_subprocesses/5.15 ``actionformer_gated`` 流水线VideoSwin → ActionFormer + 手检/好坏帧/
耗材分类投票);父进程通过 ``--events-jsonl`` tail JSONL 即可消费段事件。
"""

View File

@@ -11,7 +11,7 @@ from typing import Any
import yaml
REPO_ROOT = Path(__file__).resolve().parents[2]
DEFAULT_REFERENCE_BUNDLE_RELATIVE = "refs/5.15"
DEFAULT_REFERENCE_BUNDLE_RELATIVE = "algorithm_subprocesses/5.15"
def configured_reference_bundle_relative() -> str:

View File

@@ -60,7 +60,7 @@ HAND_DETECTION_MIN_CROP_PX: int = 64
HAND_DETECTION_DEVICE: str = ""
# --- refs/5.15 ActionFormer 实时版VideoSwin → ActionFormer + 手检/好坏帧/耗材投票)---
# --- algorithm_subprocesses/5.15 ActionFormer 实时版VideoSwin → ActionFormer + 手检/好坏帧/耗材投票)---
# 默认开启并与常见 demo 主摄 id 对齐;若缺少配置引用包 weights 下权重,开录时该路会记录异常。
ACTIONFORMER_ENABLED: bool = True
# 检查期:单路算法固定拉流 or-cam-03恢复按请求首路时请改回 "" 或按需配置)。
@@ -69,7 +69,7 @@ ACTIONFORMER_PRIMARY_CAMERA_ID: str = "or-cam-03"
# RTSP 帧率假设(用于 frame_idx → t_abs 推算与 ActionFormer fps 入参;线上需与摄像机一致)。
ACTIONFORMER_ASSUMED_FPS: float = 25.0
# 与 refs/5.15 ``run_haocai_actionformer_consumables_e2e`` 写出的 infer_single.yaml 同语义的 VideoSwin 参数:
# 与 algorithm_subprocesses/5.15 ``run_haocai_actionformer_consumables_e2e`` 写出的 infer_single.yaml 同语义的 VideoSwin 参数:
# clip_len 32, frame_stride 2, feat_stride_frames 32 → feat_num_frames=64。
VIDEOSWIN_CLIP_LEN: int = 32
VIDEOSWIN_FRAME_STRIDE: int = 2
@@ -85,7 +85,7 @@ ACTIONFORMER_HAOCAI_WEIGHTS: str = default_actionformer_haocai_weights_path()
ACTIONFORMER_TEAR_WEIGHTS: str = default_actionformer_tear_weights_path()
ACTIONFORMER_NUM_CLASSES: int = 1 # 单类Action划段与 e2e infer_single.yaml 对齐
# 与 refs/5.15 e2e 默认对齐的运行时阈值
# 与 algorithm_subprocesses/5.15 e2e 默认对齐的运行时阈值
ACTIONFORMER_DET_CONF: float = 0.5
ACTIONFORMER_PAD_RATIO: float = 0.30
ACTIONFORMER_DET_IMGSZ: int = 640

View File

@@ -193,9 +193,9 @@ class Settings(BaseSettings):
default="vision",
validation_alias=AliasChoices("VIDEO_RESULT_DOCTOR_ID", "video_result_doctor_id"),
)
#: 算法引用包目录(相对 backend 根目录,如 ``refs/5.15``);可用环境变量 ``REFERENCE_BUNDLE_RELATIVE`` 覆盖。
#: 算法子进程包目录(相对 backend 根目录,如 ``algorithm_subprocesses/5.15``);可用环境变量 ``REFERENCE_BUNDLE_RELATIVE`` 覆盖。
reference_bundle_relative: str = Field(
default="refs/5.15",
default="algorithm_subprocesses/5.15",
validation_alias=AliasChoices("REFERENCE_BUNDLE_RELATIVE", "reference_bundle_relative"),
)

View File

@@ -1,4 +1,4 @@
# 与训练 data.yaml 类名一致label_id 来自 refs/商品信息表.xlsx商品名称→产品编码同名多规格以 / 连接)。
# 与训练 data.yaml 类名一致label_id 来自 algorithm_subprocesses 离线包内商品信息表.xlsx商品名称→产品编码同名多规格以 / 连接)。
# 推理时以权重内嵌 names 为准;本文件供业务 label_id 与开录空 candidate 全量类名。
names:
0: MCuⅡ功能性宫内节育器

View File

@@ -71,7 +71,7 @@ def _orchestrate_write_rtsp_host() -> str:
response_model=VideoBatchSurgeryResponse,
summary="非实时精确模式:上传单路 MP4 并跑配置引用包 batch",
description=(
"仅当 DEMO_ORCHESTRATOR_ENABLED=true。保存上传视频调用配置引用包 main.py默认 refs/5.15"
"仅当 DEMO_ORCHESTRATOR_ENABLED=true。保存上传视频调用配置算法子进程包 main.py默认 algorithm_subprocesses/5.15"
"解析 TSV 后写入最终结果,并调用 visualize_result_video.py 生成带标签视频。"
),
)

View File

@@ -38,7 +38,7 @@ from app.domain.consumption import SurgeryConsumptionStored
@dataclass(frozen=True)
class ReferenceDoctorInfo:
"""Parsed from refs/5.15 result footer line ``医生信息:...``."""
"""Parsed from algorithm_subprocesses/5.15 result footer line ``医生信息:...``."""
doctor_id: str
doctor_name: str | None
@@ -362,7 +362,7 @@ _DOCTOR_ID_ONLY_RE = re.compile(
def parse_reference_doctor_info(path: Path) -> ReferenceDoctorInfo | None:
"""Read ``医生信息:姓名 (id=...)`` footer appended by refs/5.15 orchestrator."""
"""Read ``医生信息:姓名 (id=...)`` footer appended by algorithm_subprocesses/5.15 orchestrator."""
if not path.is_file():
return None
@@ -421,7 +421,7 @@ def parse_reference_doctor_info(path: Path) -> ReferenceDoctorInfo | None:
def is_reference_result_complete(path: Path) -> bool:
"""True when refs/5.15 orchestrator has finished writing the TSV (incl. footer)."""
"""True when algorithm_subprocesses/5.15 orchestrator has finished writing the TSV (incl. footer)."""
if not path.is_file() or path.stat().st_size <= 0:
return False
@@ -911,7 +911,7 @@ class VideoBatchRunner:
config_path=run_files.config_path.resolve(),
)
logger.info(
"reference batch starting for surgery_id={} (refs main.py, work_dir={})",
"reference batch starting for surgery_id={} (algorithm_subprocesses main.py, work_dir={})",
surgery_id,
cache_work_dir,
)

View File

@@ -34,9 +34,9 @@ dependencies = [
"scipy>=1.14.0",
"pandas>=2.2.0",
"openpyxl>=3.1.0",
# refs/5-6-code ActionFormer eval.py 导入 libs.datasets → anet.py 需要 h5py
# algorithm_subprocesses/5-6-code ActionFormer eval.py 导入 libs.datasets → anet.py 需要 h5py
"h5py>=3.13.0",
# refs actionformer libs/utils/metrics.py随 datasets 链路导入)
# algorithm_subprocesses actionformer libs/utils/metrics.py随 datasets 链路导入)
"joblib>=1.4.2",
"mediapipe>=0.10.35",
]

View File

@@ -272,13 +272,13 @@ def test_build_reference_visualization_command_uses_hand_model_and_result_tsv(
def test_build_reference_command_uses_5_15_main_py(tmp_path: Path) -> None:
cmd = build_reference_command(
bundle_dir=tmp_path / "refs" / "5.15",
bundle_dir=tmp_path / "algorithm_subprocesses" / "5.15",
config_path=tmp_path / "config.yaml",
)
assert cmd[:3] == ["uv", "run", "python"]
assert cmd[3:5] == ["-X", "faulthandler"]
assert cmd[5].endswith("refs/5.15/main.py")
assert cmd[5].endswith("algorithm_subprocesses/5.15/main.py")
assert cmd[6:] == ["--config", str(tmp_path / "config.yaml")]
@@ -286,7 +286,7 @@ def test_video_batch_runner_uses_reference_bundle_relative_env_override(
tmp_path: Path,
monkeypatch,
) -> None:
bundle = tmp_path / "refs" / "custom"
bundle = tmp_path / "algorithm_subprocesses" / "custom"
_write_minimal_reference_bundle(bundle)
video = tmp_path / "case.mp4"
video.write_bytes(b"same-video")
@@ -305,7 +305,7 @@ def test_video_batch_runner_uses_reference_bundle_relative_env_override(
output.write_text(_complete_result_tsv_body(), encoding="utf-8")
return _Proc()
monkeypatch.setenv("REFERENCE_BUNDLE_RELATIVE", "refs/custom")
monkeypatch.setenv("REFERENCE_BUNDLE_RELATIVE", "algorithm_subprocesses/custom")
monkeypatch.setattr(reference_bundle_runtime, "REPO_ROOT", tmp_path)
monkeypatch.setattr("app.services.video_batch_runner.subprocess.run", fake_run)

View File

@@ -324,7 +324,7 @@
<p class="small muted" style="margin:8px 0 0">
<label style="display:inline-flex;align-items:flex-start;gap:8px;cursor:pointer;max-width:52rem">
<input type="checkbox" id="video-batch-mode" style="margin-top:2px" />
<span><strong>非实时精确模式</strong>:使用调试区「路 1」上传的完整 MP4调用主 FastAPI 的 <code>POST /internal/demo/video-batch-surgery</code>,复用 <code>refs/5.15/main.py</code> 并在完成后生成带标签视频。该模式不会启动 RTSP 实时会话,处理完成后用查询结果接口查看。</span>
<span><strong>非实时精确模式</strong>:使用调试区「路 1」上传的完整 MP4调用主 FastAPI 的 <code>POST /internal/demo/video-batch-surgery</code>,复用 <code>algorithm_subprocesses/5.15/main.py</code> 并在完成后生成带标签视频。该模式不会启动 RTSP 实时会话,处理完成后用查询结果接口查看。</span>
</label>
</p>
<div class="actions">
@@ -549,7 +549,7 @@
player.onloadeddata = () => {
if (hint) {
hint.innerHTML =
`已加载手部打框+耗材标签视频(refs/5.15 visualize_result_video.py` +
`已加载手部打框+耗材标签视频(algorithm_subprocesses/5.15 visualize_result_video.py` +
`<a href="${src}" target="_blank" rel="noreferrer">${path}</a>`;
}
};

View File

@@ -1,4 +1,4 @@
# 与训练 data.yaml 类名一致label_id 来自 refs/商品信息表.xlsx商品名称→产品编码同名多规格以 / 连接)。
# 与训练 data.yaml 类名一致label_id 来自 algorithm_subprocesses 离线包内商品信息表.xlsx商品名称→产品编码同名多规格以 / 连接)。
# 推理时以权重内嵌 names 为准;本文件供业务 label_id 与开录空 candidate 全量类名。
names:
0: MCuⅡ功能性宫内节育器