Skip to content

Commit 0b1455b

Browse files
Changes to use model and video url from config and updated 3dpose video url (#2017)
1 parent 6cdc3fe commit 0b1455b

File tree

5 files changed

+106
-50
lines changed

5 files changed

+106
-50
lines changed

health-and-life-sciences-ai-suite/multi_modal_patient_monitoring/configs/model-config.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ ai-ecg:
44
type: ai-ecg
55
hub: hls
66
target_dir: /models/ai-ecg
7+
nodel_url: https://raw.githubusercontent.com/Einse57/OpenVINO_sample/master/ai-ecg-master
78
ir_file: ecg_8960_ir10_fp16.xml
89
video_dir: /videos/ai-ecg
910
- name: ecg_17920_ir10_fp16
1011
type: ai-ecg
1112
hub: hls
1213
target_dir: /models/ai-ecg
14+
nodel_url: https://raw.githubusercontent.com/Einse57/OpenVINO_sample/master/ai-ecg-master
1315
ir_file: ecg_17920_ir10_fp16.xml
1416
video_dir: /videos/ai-ecg
1517

@@ -20,13 +22,17 @@ rppg:
2022
hub: hls
2123
target_dir: /models/rppg
2224
model_file: mtts_can.hdf5
25+
model_url: https://github.com/xliucs/MTTS-CAN/raw/main/mtts_can.hdf5
2326
video_dir: /videos/rppg
27+
video_url: https://github.com/opencv/opencv/raw/master/samples/data/vtest.avi
2428

2529
pose-3d:
2630
models:
2731
- name: human-pose-estimation-3d-0001
2832
type: 3d-pose
2933
hub: hls
3034
target_dir: /models/3d-pose
35+
model_url: https://storage.openvinotoolkit.org/repositories/open_model_zoo/public/2022.1/human-pose-estimation-3d-0001/human-pose-estimation-3d.tar.gz
3136
ir_file: human-pose-estimation-3d-0001.xml
3237
video_dir: /videos/3d-pose
38+
video_url: https://www.pexels.com/download/video/6130537

health-and-life-sciences-ai-suite/multi_modal_patient_monitoring/services/patient-monitoring-assets/Dockerfile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ WORKDIR /app
2626
# Python deps for asset generation
2727
# ----------------------------
2828
COPY requirements.txt /app/requirements.txt
29-
RUN pip install --no-cache-dir -r /app/requirements.txt
29+
RUN pip install --default-timeout=300 --retries 5 --no-cache-dir -r /app/requirements.txt
3030

3131
# ----------------------------
3232
# App scripts used to build assets (model-config.yaml is mounted at runtime)
@@ -54,7 +54,6 @@ ARG HTTPS_PROXY
5454
ARG NO_PROXY
5555

5656

57-
5857
WORKDIR /app
5958

6059
# Minimal system deps (no heavy ML frameworks here)

health-and-life-sciences-ai-suite/multi_modal_patient_monitoring/services/patient-monitoring-assets/scripts/3d_pose_model_convert.py

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,20 @@
1515
CONFIG_PATH = Path("/app/configs/model-config.yaml")
1616

1717

18-
def _load_pose_model_config() -> tuple[str, str, str]:
19-
"""Load 3D pose model name, target_dir, and video_dir from config.
18+
def _load_pose_model_config() -> tuple[str, str, str, str, str]:
19+
"""Load 3D pose model settings from config.
2020
2121
This function expects /app/configs/model-config.yaml to exist and to
22-
define pose-3d.models[0] with at least name, target_dir, and
23-
video_dir. If any of these are missing or the file is not readable,
24-
the script will raise and fail fast instead of using hardcoded
25-
defaults.
22+
define pose-3d.models[0] with at least:
23+
24+
- name
25+
- target_dir
26+
- model_url
27+
- video_dir
28+
- video_url
29+
30+
If any of these are missing or the file is not readable, the script
31+
will raise and fail fast instead of using hardcoded defaults.
2632
"""
2733
if not CONFIG_PATH.exists():
2834
raise FileNotFoundError(
@@ -45,17 +51,26 @@ def _load_pose_model_config() -> tuple[str, str, str]:
4551
first = models[0] or {}
4652
name = first.get("name")
4753
target_dir = first.get("target_dir")
54+
model_url = first.get("model_url")
4855
video_dir = first.get("video_dir")
56+
video_url = first.get("video_url")
4957

50-
if not name or not target_dir or not video_dir:
58+
if not name or not target_dir or not model_url or not video_dir or not video_url:
5159
raise ValueError(
52-
"pose-3d.models[0] must define name, target_dir, and video_dir in model-config.yaml."
60+
"pose-3d.models[0] must define name, target_dir, model_url, "
61+
"video_dir, and video_url in model-config.yaml."
5362
)
5463

55-
return str(name), str(target_dir), str(video_dir)
64+
return (
65+
str(name),
66+
str(target_dir),
67+
str(video_dir),
68+
str(model_url),
69+
str(video_url),
70+
)
5671

5772

58-
MODEL_NAME, MODEL_TARGET_DIR, MODEL_VIDEO_DIR = _load_pose_model_config()
73+
MODEL_NAME, MODEL_TARGET_DIR, MODEL_VIDEO_DIR, MODEL_URL, VIDEO_URL = _load_pose_model_config()
5974

6075
# Directory where the 3D pose model assets will be stored
6176
# Use the same default as omz-model-download.sh: /models/3d-pose
@@ -78,22 +93,14 @@ def _load_pose_model_config() -> tuple[str, str, str]:
7893
ov_model_path = base_model_dir / f"{MODEL_NAME}.xml"
7994

8095
# Demo video path
81-
video_url = "https://storage.openvinotoolkit.org/data/test_data/videos/face-demographics-walking.mp4"
8296
video_path = videos_dir / "face-demographics-walking.mp4"
8397

8498

8599
# 1) Download and extract the .pth checkpoint if needed
86100
if not ckpt_file.exists():
87-
# URL still points to the default OMZ model; MODEL_NAME controls
88-
# the local file naming via config.
89-
url = (
90-
"https://storage.openvinotoolkit.org/repositories/open_model_zoo/public/2022.1/"
91-
"human-pose-estimation-3d-0001/human-pose-estimation-3d.tar.gz"
92-
)
93-
94101
if not tar_path.exists():
95-
print(f"Downloading 3D pose checkpoint from {url}")
96-
urllib.request.urlretrieve(url, tar_path)
102+
print(f"Downloading 3D pose checkpoint from {MODEL_URL}")
103+
urllib.request.urlretrieve(MODEL_URL, tar_path)
97104
print(f"Saved checkpoint archive to {tar_path}")
98105

99106
print(f"Extracting checkpoint archive into {base_model_dir}")
@@ -104,8 +111,19 @@ def _load_pose_model_config() -> tuple[str, str, str]:
104111

105112
# 1b) Download the demo video if needed
106113
if not video_path.exists():
107-
print(f"Downloading 3D pose demo video from {video_url}")
108-
urllib.request.urlretrieve(video_url, video_path)
114+
print(f"Downloading 3D pose demo video from {VIDEO_URL}")
115+
# Pexels blocks the default Python user-agent; mimic a browser and
116+
# send a valid Referer so the request matches typical browser usage.
117+
req = urllib.request.Request(
118+
VIDEO_URL,
119+
headers={
120+
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
121+
"(KHTML, like Gecko) Chrome/120.0 Safari/537.36",
122+
"Referer": "https://www.pexels.com/",
123+
},
124+
)
125+
with urllib.request.urlopen(req) as resp, video_path.open("wb") as out_f:
126+
shutil.copyfileobj(resp, out_f)
109127
print(f"Saved 3D pose demo video to {video_path}")
110128

111129

@@ -141,4 +159,4 @@ def _load_pose_model_config() -> tuple[str, str, str]:
141159
except FileNotFoundError:
142160
pass
143161

144-
print("✅ OpenVINO IR model saved:", ov_model_path)
162+
print("✅ OpenVINO IR model saved:", ov_model_path)

health-and-life-sciences-ai-suite/multi_modal_patient_monitoring/services/patient-monitoring-assets/scripts/ecg_download_assets.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ def download_file(url: str, dest: Path, desc: str) -> None:
2828
raise
2929

3030

31-
def load_ecg_models_from_config() -> list[tuple[Path, str, str]]:
31+
def load_ecg_models_from_config() -> list[tuple[Path, str, str, str]]:
3232
"""Load ECG model directories and filenames from model-config.yaml.
3333
34-
Returns a list of tuples: (target_dir, xml_filename, bin_filename).
34+
Returns a list of tuples: (target_dir, xml_filename, bin_filename, model_url).
3535
This function expects /app/configs/model-config.yaml to exist and to
3636
define ai-ecg.models[*] entries with at least target_dir and
3737
ir_file or name. If the file is missing or malformed, it will
@@ -61,6 +61,7 @@ def load_ecg_models_from_config() -> list[tuple[Path, str, str]]:
6161
target_dir_val = m.get("target_dir")
6262
ir_file_val = m.get("ir_file")
6363
name_val = m.get("name")
64+
model_url_val = m.get("model_url")
6465

6566
if not target_dir_val:
6667
raise ValueError(
@@ -86,7 +87,19 @@ def load_ecg_models_from_config() -> list[tuple[Path, str, str]]:
8687
)
8788

8889
bin_file = xml_file.replace(".xml", ".bin")
89-
result.append((target_dir, xml_file, bin_file))
90+
91+
# model_url is optional in config for backward compatibility; if
92+
# omitted, fall back to the legacy BASE_URL.
93+
if not model_url_val:
94+
logger.warning(
95+
"ai-ecg.models entry missing model_url; falling back to BASE_URL %s",
96+
BASE_URL,
97+
)
98+
model_url = BASE_URL
99+
else:
100+
model_url = str(model_url_val)
101+
102+
result.append((target_dir, xml_file, bin_file, model_url))
90103

91104
return result
92105

@@ -96,7 +109,7 @@ def main() -> int:
96109

97110
models = load_ecg_models_from_config()
98111

99-
for target_dir, xml_name, bin_name in models:
112+
for target_dir, xml_name, bin_name, model_url in models:
100113
target_dir.mkdir(parents=True, exist_ok=True)
101114
logger.info("Using ECG model directory: %s", target_dir)
102115

@@ -106,7 +119,7 @@ def main() -> int:
106119
logger.info("%s already exists, skipping", dest)
107120
continue
108121

109-
url = f"{BASE_URL}/{fname}"
122+
url = f"{model_url}/{fname}"
110123
download_file(url, dest, fname)
111124

112125
logger.info("ECG models ready")

health-and-life-sciences-ai-suite/multi_modal_patient_monitoring/services/patient-monitoring-assets/scripts/rppg_download_assets.py

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,20 @@
3434
CONFIG_PATH = Path("/app/configs/model-config.yaml")
3535

3636

37-
def _load_rppg_model_config() -> tuple[str, str]:
38-
"""Load rPPG model name and target_dir from config.
37+
def _load_rppg_model_config() -> tuple[str, str, str, str, str]:
38+
"""Load rPPG model and video settings from config.
3939
4040
This function expects /app/configs/model-config.yaml to exist and to
41-
define rppg.models[0] with at least name and target_dir. If these
42-
are missing or the file is not readable, the script will raise and
43-
fail fast instead of using hardcoded defaults.
41+
define rppg.models[0] with at least:
42+
43+
- name
44+
- target_dir
45+
- model_url
46+
- video_dir
47+
- video_url
48+
49+
If any of these are missing or the file is not readable, the script
50+
will raise and fail fast instead of using hardcoded defaults.
4451
"""
4552
if not CONFIG_PATH.exists():
4653
raise FileNotFoundError(
@@ -63,13 +70,23 @@ def _load_rppg_model_config() -> tuple[str, str]:
6370
first = models[0] or {}
6471
name = first.get("name")
6572
target_dir = first.get("target_dir")
73+
model_url = first.get("model_url")
74+
video_dir = first.get("video_dir")
75+
video_url = first.get("video_url")
6676

67-
if not name or not target_dir:
77+
if not name or not target_dir or not model_url or not video_dir or not video_url:
6878
raise ValueError(
69-
"rppg.models[0] must define name and target_dir in model-config.yaml."
79+
"rppg.models[0] must define name, target_dir, model_url, video_dir, "
80+
"and video_url in model-config.yaml."
7081
)
7182

72-
return str(name), str(target_dir)
83+
return (
84+
str(name),
85+
str(target_dir),
86+
str(model_url),
87+
str(video_dir),
88+
str(video_url),
89+
)
7390

7491

7592
@keras.utils.register_keras_serializable(package="Custom")
@@ -135,11 +152,10 @@ def download_model() -> None:
135152
"""Download MTTS-CAN model weights.
136153
137154
The destination filename under /models/rppg is taken from
138-
model-config.yaml (rppg.models[0].name), falling back to
139-
"mtts_can.hdf5" if not configured.
155+
model-config.yaml (rppg.models[0].name) and the download URL from
156+
rppg.models[0].model_url.
140157
"""
141-
MODEL_URL = "https://github.com/xliucs/MTTS-CAN/raw/main/mtts_can.hdf5"
142-
model_filename, target_dir = _load_rppg_model_config()
158+
model_filename, target_dir, model_url, _, _ = _load_rppg_model_config()
143159
model_path = Path(target_dir) / model_filename
144160

145161
if model_path.exists():
@@ -149,11 +165,11 @@ def download_model() -> None:
149165
return
150166

151167
logger.info("Downloading MTTS-CAN model...")
152-
logger.info(f" Source: {MODEL_URL}")
168+
logger.info(f" Source: {model_url}")
153169
logger.info(f" Destination: {model_path}")
154170

155171
try:
156-
download_file(MODEL_URL, model_path, "Model")
172+
download_file(model_url, model_path, "Model")
157173
logger.info("✓ Model downloaded successfully")
158174
size_mb = model_path.stat().st_size / (1024 * 1024)
159175
logger.info(f" Size: {size_mb:.1f} MB")
@@ -168,7 +184,7 @@ def convert_model_to_openvino() -> None:
168184
Produces /models/rppg/mtts_can.xml and .bin, which will be used by the
169185
rPPG service running on GPU.
170186
"""
171-
model_filename, target_dir = _load_rppg_model_config()
187+
model_filename, target_dir, _, _, _ = _load_rppg_model_config()
172188
h5_path = Path(target_dir) / model_filename
173189
# Keep the IR filename stable; config controls input HDF5 name.
174190
xml_path = Path(target_dir) / "mtts_can.xml"
@@ -198,9 +214,13 @@ def convert_model_to_openvino() -> None:
198214

199215

200216
def download_video() -> None:
201-
"""Download sample video."""
202-
VIDEO_URL = "https://github.com/opencv/opencv/raw/master/samples/data/vtest.avi"
203-
video_path = Path("/videos") / "rppg" / "sample.mp4"
217+
"""Download sample video.
218+
219+
The destination directory and download URL are taken from
220+
model-config.yaml (rppg.models[0].video_dir and video_url).
221+
"""
222+
_, _, _, video_dir, video_url = _load_rppg_model_config()
223+
video_path = Path(video_dir) / "sample.mp4"
204224

205225
if video_path.exists():
206226
logger.info(f"Video already exists: {video_path}")
@@ -209,11 +229,11 @@ def download_video() -> None:
209229
return
210230

211231
logger.info("Downloading sample video...")
212-
logger.info(f" Source: {VIDEO_URL}")
232+
logger.info(f" Source: {video_url}")
213233
logger.info(f" Destination: {video_path}")
214234

215235
try:
216-
download_file(VIDEO_URL, video_path, "Video")
236+
download_file(video_url, video_path, "Video")
217237
logger.info("✓ Video downloaded successfully")
218238
size_mb = video_path.stat().st_size / (1024 * 1024)
219239
logger.info(f" Size: {size_mb:.1f} MB")

0 commit comments

Comments
 (0)