"""Model acquisition: download YuNet, copy reusable models from the old projects on this machine when present. Idempotent — safe to re-run.""" from __future__ import annotations import logging import shutil import ssl import urllib.error import urllib.request from pathlib import Path log = logging.getLogger(__name__) YUNET_URL = ("https://github.com/opencv/opencv_zoo/raw/main/models/" "face_detection_yunet/face_detection_yunet_2023mar.onnx") BUFFALO_SC_URL = ("https://github.com/deepinsight/insightface/releases/" "download/v0.7/buffalo_sc.zip") RECOGNIZERS = ["adaface_ir101.onnx", "adaface_ir50.onnx", "w600k_r50.onnx", "arcface_int8.onnx", "w600k_mbf.onnx", "arcface.onnx"] # Known locations of reusable models from the previous projects. _LEGACY_MODEL_DIRS = [ Path(r"D:\NEARLE\WOrking now\RTSP_16072025\pattern_reg\models"), ] BUFFALO_L_URL = ("https://github.com/deepinsight/insightface/releases/" "download/v0.7/buffalo_l.zip") # target filename -> legacy filename _COPY_MAP = { "arcface.onnx": "arcface.onnx", "age_deploy.prototxt": "age_deploy.prototxt", "age_net.caffemodel": "age_net.caffemodel", "gender_deploy.prototxt": "gender_deploy.prototxt", "gender_net.caffemodel": "gender_net.caffemodel", "emotion-ferplus-8.onnx": "emotion-ferplus-8.onnx", } def _https_context() -> "ssl.SSLContext | None": """The CA store to trust, or None to use whatever Python defaults to. Returning None first is deliberate. On Windows and on a Homebrew or system Python, the default context reads the machine's own certificate store - which is what makes a corporate proxy with its own root CA work. Replacing that with certifi's bundle unconditionally would break every site that has one, in order to fix a different platform. The platform this fixes is a python.org macOS build. It ships its own OpenSSL with NO trust store, and populates one only when somebody double-clicks `Install Certificates.command` in the Python folder - which nobody installing face-recognition software has any reason to know about. Every HTTPS request from that interpreter fails with: ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate Measured on a colleague's Mac: the engine installed perfectly and then could not download a 230 KB model file, ending setup in forty lines of traceback about `_ssl.c`. """ try: import certifi except ImportError: # pragma: no cover - certifi ships with requests return None return ssl.create_default_context(cafile=certifi.where()) def _is_cert_failure(err: BaseException) -> bool: """Is this a certificate-verification failure, however it is wrapped? `urllib` does NOT let `ssl.SSLCertVerificationError` out. It catches it and re-raises `urllib.error.URLError(err)`, carrying the original on `.reason` - so `except ssl.SSLCertVerificationError` around `urlopen` matches nothing, ever. That is not a subtlety this file gets to record academically: the first version of the fallback below was written exactly that way, shipped, and failed on the machine it was written for with the very traceback it was meant to prevent. The unit test passed throughout, because the fake it used raised the bare SSL error - a shape real urllib never produces. A stub that agrees with the author is worse than no test, and the test now raises what urllib raises. """ reason = getattr(err, "reason", None) return isinstance(err, ssl.SSLCertVerificationError) or \ isinstance(reason, ssl.SSLCertVerificationError) def _urlopen(url: str, timeout: float = 60.0): """Open a URL, falling back to certifi's CA bundle on a verify failure. Default first, certifi second, so the fix is additive: a machine whose own store works keeps using it, and one with no store at all gets a bundle rather than a traceback. certifi is already here - `requests` is a hard dependency and brings it. """ try: return urllib.request.urlopen(url, timeout=timeout) except (urllib.error.URLError, ssl.SSLCertVerificationError) as err: # Only a certificate problem is worth a second attempt. "No route to # host" and "connection refused" arrive as URLError too, and retrying # those with a different CA list changes nothing except how long the # operator waits for the real message. if not _is_cert_failure(err): raise ctx = _https_context() if ctx is None: raise log.info("the system certificate store could not verify %s; " "using the bundled CA list", url.split("/")[2]) return urllib.request.urlopen(url, timeout=timeout, context=ctx) def _fetch(url: str, dest: Path, label: str) -> None: """Download with progress on stdout the supervisor can read. On first run this is minutes of nothing: the API is not up yet, so the app cannot ask the engine what it is doing, and a shop PC that shows a stopped engine for five minutes after install looks broken. The supervisor watches for `download: