vuer_cv

The computer-vision inference microservice of FaceKom. It exposes face/document/biometric ML over an HTTP REST API (Falcon + uWSGI) and a streaming WebSocket API (WebRTC/websockets), backed by a fleet of per-model worker processes that talk to the front-ends over a Redis-backed RPC bus. Base branch: devel. Version at HEAD: 4.9.1 (config/docker.json:54, changelog.md:1).

Source-only clone. data/** is Git-LFS (.gitattributes:1); the *.onnx/*.pth/*.skops/*.npz/*.pkl model weights present here are LFS pointer files, not real binaries (verified: data/ghostnetv2_w1_3_s2.onnx begins version https://git-lfs.github.com/spec/v1, oid sha256:…, size 27038712). They were never opened.

No Dockerfile exists in this repo (searched: none found). The runtime image is prebuilt and pulled from a registry — CI uses harbor.techteamer.com/facekom-devel/vuer_cv_dev:latest (.travis.yml:42,75). The Python source mounts into /workspace/vuer_cv inside that image; the image supplies the OS, system libs (nginx, redis, tesseract), and the Python interpreter. This repo carries only the app code, requirements, supervisor/nginx/uwsgi config, and ML model pointers.

See also: architecture-overview, customization-architecture, customization-branch-catalog.


1. Purpose & role in FaceKom

vuer_cv is the CV engine. It performs (verified from HTTP routes app_http.py:66-89, WebSocket task map server/websocket/task/__init__.py:59-74, and the ONNX model table in Readme.md:166-192):

  • Face: detection, encoding/comparison (cosine distance), landmark detection, draw, reference-face extraction, gender/age, sunglasses, presentation-attack detection (PAD), deepfake detection.
  • Documents/ID cards: localization/warp (corner detector), classification, OCR (generic + per-document templated), MRZ reading (Passporteye/Tesseract), card-integrity check, document recognition v2/v3.
  • Other CV: barcode detect/decode (pyzbar + Detectron2), text detection (FAST), background masking (MODNet), sharpness estimation, kaptcha OCR, speech detection (Silero VAD), liveness (v1/v2, interactive/deterministic), hologram detection (image/video, v1/v2), streaming player.

It is a leaf service: it depends on Redis (in-process via unix socket) and an upstream Nginx; this repo contains no evidence of it calling other FaceKom services (see §9).


2. Tech stack & runtime

AspectValueSource
LanguagePython (uses 3.10+ syntax: `strNone, walrus, match`-free)
HTTP frameworkFalcon 4.2.0 + falcon-multipartrequirements/requirements.in:17,19, app_http.py:32-33
WSGI serveruWSGI 2.0.31requirements/requirements.in:15, uwsgi_vuer_cv_docker.ini
WebSocketwebsockets 16.0, uvloop 0.22.1requirements/requirements.in:31,16, app_websocket.py
WebRTCaiortc 1.14.0, av 16.1.0, pyeerequirements/requirements.in:32,30,33
RPC busRedis 7.4.0 (redis-py) over unix socketrequirements/requirements.in:16, config/docker.json:3-6
ML runtimeonnxruntime-gpu 1.24.4, torch 2.12.0+cpu, torchvision 0.27.0+cpu, easyocr 1.7.2, scikit-learn 1.8.0, skops, Detectron2 (from image)requirements/requirements.in:36,46-47,11,27-28
Image/CV libsopencv-python-headless 4.13, Pillow 12.2, numpy 2.4.5, scipy, shapely, scikit-image, imageiorequirements/requirements.in
MRZlocal vendored PassportEye + pytesseractpackages/passporteye/, requirements/requirements-2.in:6
Process mgrsupervisordsupervisor_vuer_cv_docker.conf
Reverse proxynginx (templated via Jinja2)nginx_vuer_cv_docker.conf.j2, setup/generate_nginx_conf.py
Logginglogurueverywhere
Package managerpip + pip-tools (pip-compile)requirements/compile.sh, requirements/install.sh
Config mergejsonmerge + jsonschema (Draft 7)server/cfg.py:5,79

requirements.in does not pin Python itself, and there is no engines/python_requires field. The interpreter version is fixed by the prebuilt image, not by this repo. Code uses Python ≥3.10 union syntax (server/appcache.py:37,71).

setuptools is deliberately not in requirements.in (commented # IGNORED BY PIP-COMPILE! Part of environment install in Dockerfile!, requirements/requirements.in:2) — it is installed by the image build, which lives in another repo.


3. Build & run

Entrypoints

There are 10 top-level app_*.py entrypoints plus setup scripts. Each app_* boots Redis, an AppCache, optionally warms up models, then either serves WSGI (app_http) / WebSocket (app_websocket) or runs a blocking RedisRpcServer loop on a named queue.

EntrypointRoleRPC queue / portSource
app_http.pyFalcon WSGI app (application global), 24 REST routes (24 add_route( calls, app_http.py:66-89)uWSGI socket 127.0.0.1:40081app_http.py:63-97, uwsgi_vuer_cv_docker.ini:23
app_websocket.pyasyncio WebSocket server, dispatches taskType→CV tasklistens 40082 + workerapp_websocket.py:108-115
app_face.pyface detect/encode/compare/landmark/gender-age/sunglassesRPC faceapp_face.py:170-188
app_card_detector.pycard warp/classify/integrityRPC cardDetectorapp_card_detector.py:65-73
app_ocr.pykaptcha + generic + document OCRRPC ocrapp_ocr.py:83-89
app_text_detector.pyFAST text detectionRPC textDetectorapp_text_detector.py:50-54
app_detectron2.pybarcode detection (Detectron2)RPC detectron2app_detectron2.py:36-42
app_mrz.pyMRZ reading (Passporteye/Tesseract)RPC mrzapp_mrz.py:168-175
app_pad.pypresentation-attack + deepfake detectionRPC padapp_pad.py:41-48
app_onnx.pybackground masking (MODNet) + speech detection (VAD)RPC onnxapp_onnx.py:40-45

app_onnx.py and app_pad.py always run numprocs=1 (hard-coded in supervisor_vuer_cv_docker.conf:96,201); all others scale via ENV_NUM_*_PROCESSES env vars produced from config (see §7).

app_ocr.py cannot run multiple in-process worker threads — comment at app_ocr.py:91-92: a Python bug conflicts with DocumentOcrEngine's ThreadPoolExecutor causing "cannot schedule new futures after interpreter shutdown". It always runs a single rpcServer.run().

Start sequence (production / PYTHON_ENV=docker)

  1. docker_entrypoint.shsource ./prepare.sh then supervisord -n -c /etc/supervisor/supervisord.conf (docker_entrypoint.sh:5-7).
  2. prepare.sh (prepare.sh:6-12):
    • python setup/load_config_into_env_file.py <tmpfile> → writes NUM_<KEY>_PROCESSES env vars from config.scaling.*.processes.
    • source that tmpfile into the environment.
    • python setup/generate_nginx_conf.py nginx_vuer_cv_$PYTHON_ENV.conf → renders the .j2 template with server_count = NUM_WEBSOCKET_PROCESSES.
  3. supervisord launches programs (supervisor_vuer_cv_docker.conf): nginx, redis, vuer_cv (uWSGI running app_http.py with --processes $NUM_HTTP_PROCESSES), and numprocs-scaled vuer_cv_ws / vuer_cv_detectron / vuer_cv_onnx / vuer_cv_text_detector / vuer_cv_ocr / vuer_cv_card_detector / vuer_cv_face / vuer_cv_pad / vuer_cv_mrz.

prepare.sh overwrites nginx_vuer_cv_$ENV.conf on every container start (Readme.md:160-164). Put custom Nginx changes in a copy of the .j2 template, never in the generated file.

package.json scripts

None. This is a Python repo; there is no package.json anywhere in-tree (the only JS lives under web/manualtest/**, served statically by Nginx, with no build step or package.json). The closest equivalents are the shell helper scripts below.

First-party shell/helper scripts (verbatim behavior)

ScriptWhat it doesSource
docker_entrypoint.shcontainer PID 1: source prepare.sh, exec supervisord -ndocker_entrypoint.sh
prepare.shgenerate scaling env vars + render nginx conf (see above)prepare.sh
requirements/compile.shdev-only (exit 1 if PYTHON_ENV != dev): pip-compile each requirements*.in (+ optional --upgrade)requirements/compile.sh:9-21
requirements/install.shdev: pip install -r all three .txt; non-dev: same with --no-cache-dir (no dev reqs)requirements/install.sh:7-14
tests/runcoverage.shfull CI test+coverage+Trivy pipeline (see §8)tests/runcoverage.sh
bin/benchmark/run.shbenchmark runner (under bin/benchmark/)bin/benchmark/run.sh

4. Top-level structure

PathPurposeVerified
app_*.py (×10)Process entrypoints (HTTP, WS, + 8 RPC model workers)read all 10
server/Core application: config, RPC, HTTP resources, WS, CV engines, document templates, utilslisted + sampled
server/cfg.pyConfig loader/validator (merge JSONs, AJV-style schema checks, env-version gate)read
server/appcache.pyRedis-backed image/audio/metadata store; NumPyImageWrapper, channel-order conversionread
server/rpc/pyredisrpc.pyRedisRpcServer / RedisRpcClient (Redis list-based RPC; based on pyredisrpc, MIT)read
server/http/resources/24 *.py files (server/http/resources/*.py, no nested dirs) = 23 Falcon resource classes (one per endpoint) + __init__.pylisted + sampled face_compare.py
server/http/exeption_handler.py, server/utils/http_not_found.pyglobal error + 404 sinkreferenced app_http.py:59-60
server/cv/16 CV “engine” modules orchestrating model calls (server/cv/*_engine.py) + 3 holo/ utilities (19 .py files total)listed
server/cv/holo/hologram math: holo_calculator.py, holo_stack.py, holo_warp.pylisted
server/documents/17 per-document ROI/template classes (hun_*, srb_*) + registry __init__.pylisted + read __init__.py
server/websocket/WS connection, stream handler, processor/, framestore/, task/listed
server/websocket/task/14 streaming CV task types + taskMap registryread __init__.py
server/websocket/processor/per-domain frame processors (face, document, barcode, holo, holo_v2, mrz, sharpness, speech)listed
server/websocket/framestore/frame buffers (numpy / raw / audio)listed
server/utils/shared helpers: face, image, lazy_image, liveness, roi, warmup, webrtc, processing, …listed + sampled
ml/Per-model inference packages (<model>/main.py + <Model>.py) + ml/utils.py, ml/ml_model_runner.py, ml/lstm_base.pylisted + read utils.py, ml_model_runner.py
bin/40+ first-party CLI test/eval/visualization scripts (see §5)listed + read key ones
bin/benchmark/v1/v3 benchmark scripts + run.sh + benchmarking.mdlisted
config/dev.json, docker.json, jsonschemas.json, scaling_presets/read all
requirements/*.in source + *.txt pinned + compile.sh / install.shread
setup/load_config_into_env_file.py, generate_nginx_conf.pyread both
packages/passporteye/vendored MRZ library (first-party fork; installed via requirements-2.in)listed + manifest
tests/pytest suites + utils/ clients + load_test/ + runcoverage.shread key files
web/manualtest/static HTML/JS manual test harness per feature (served by nginx at /)listed
docs/a few HTTP API markdown notes (docs/http/api-v1/…, docs/misc/…)listed
data/LFS model weights + metrics/benchmark CSVs/PNGs + class-id mapping JSONlisted (pointers)
log/, tmp/runtime dirs (.gitkeep)listed
Root config.pylintrc, .coveragerc, .travis.yml, .trivyignore, build.ignore, sonar-project.properties, .editorconfig, changelog.md, Readme.md, PULL_REQUEST_TEMPLATE.mdread most
*.ini / *.j2 / *.confuWSGI ini, nginx templates, supervisor confs (each in _dev + _docker variant)read docker variants

5. Every helper script under bin/

bin/ holds first-party developer/CI tooling (excluded from coverage via .coveragerc:4). All *_testing.py scripts are CLI harnesses (argparse) that exercise an endpoint or WS task against a running server; *_evaluation.py run dataset evaluations and write CSVs. Descriptions below are the verbatim argparse description= strings (read from each file).

ScriptDescription / roleSource
bin/utils.pyshared helpers: prettyJson, loadFromJson, saveToJson, saveDebugImage, saveBenchmark, writeCsv (writes to /workspace/vuer_cv/data/benchmarks/)read fully
bin/test_case.pybase TestCase scaffolding (imports ArgumentParser) used by the testing scriptsbin/test_case.py:1
bin/healthcheck.pycalls StatusEngine.getServerStatus(level), prints JSON, exit(1) if status != green; `-l/—level basicmedium
bin/check_env_version.pyimports server.cfg.config and logs the satisfied requiredEnvVersion (env-version gate smoke test)read fully
bin/action_detection_testing.py”Test liveness detection with prerecorded input.” (action task)argparse
bin/barcode_detection_testing.py”Test barcode detection on video”argparse
bin/barcode_testing.py”Test Barcode detection endpoint”argparse
bin/deterministic_liveness_detection_testing.py”Test deterministic liveness detection”argparse
bin/document_ocr_evaluation.py”Evaluate document OCR on dataset with ground truth”argparse
bin/document_recognition_video_testing.py”Test document detection on video stream”argparse
bin/document-recognition-evaluation.py”Tests the performance of detectron2 and outputs the result in a csv file” (images 1920×1440 or 1440×1920)argparse + header comment
bin/holo_evaluation.py”Rerun hologram detections and compare results to previous ones”argparse
bin/holo_tester.py”Test hologram detection with multiple tasks running in parallel.”argparse
bin/holo_testing.py”Test hologram detection with prerecorded input.”argparse
bin/holo_v1_testing.py”Test hologram detection v1 with prerecorded (wrapped) image input”argparse
bin/holo_v2_testing.py”Test hologram detection v2 with prerecorded image input.”argparse
bin/interactive_liveness_detection_testing.py”Test interactive liveness detection”argparse
bin/liveness_analyzer.py”Analyze prerecorded liveness videos.”argparse
bin/liveness_testing.py”Test liveness detection with prerecorded input.”argparse
bin/liveness_v2_testing.py”Test liveness detection with prerecorded input.” (v2)argparse
bin/modnet_inference_onnx.pystandalone MODNet ONNX background-matting inference (module docstring)bin/modnet_inference_onnx.py:1
bin/mrz_websocket_testing.py”Test MRZ detection on video stream”argparse
bin/pad_detection_testing.py”Test video file upload.” (PAD task)argparse
bin/sharpness_testing.py”Test sharpness detection with prerecorded input.”argparse
bin/speech_detection_testing.py”Test speech detection with prerecorded input.”argparse
bin/stream_player_req_offer_testing.py”Test stream player with prerecorded input” (request-offer flow)argparse
bin/stream_player_send_offer_testing.py”Test stream player with prerecorded input” (send-offer flow)argparse
bin/visualize_face_rois.pyvisualize face ROIs (argparse desc reused: “Test hologram detection with prerecorded input.”)argparse
bin/visualize_holo_rois.pyvisualize hologram ROIs (argparse desc reused: “Test hologram detection with prerecorded input.”)argparse
bin/ws_connection_limit_testing.py”Test WS connection limit” — verifies nginx caps active connections per WS server to oneargparse + comment
bin/benchmark/run.shbenchmark suite runnerlisted
bin/benchmark/v1-*.py, v3-document-recognize.pyper-feature benchmark scripts (barcode-detection, document-ocr, face-compare, face-detect, mrz, document-recognize)listed
bin/benchmark/benchmarking.mdbenchmark docslisted

Several visualize_* / *_testing scripts share copy-pasted argparse descriptions (e.g. visualize_face_rois.py says "Test hologram detection…"). Trust the filename for intent, not the stale description string.


6. Key modules / services / entities

RPC bus — server/rpc/pyredisrpc.py

The backbone. RedisRpcServer(queue, redis) blocks on redis.blpop("rpc:" + queue), parses a JSON request {id, method, params:[args,kwargs], tmchk?}, dispatches to a registered method, and rpushes the JSON result (encoded with a NumpyEncoder that .tolist()s ndarrays) to key rpc:<id> with a 60s expiry (pyredisrpc.py:34-112). RedisRpcClient.call sets a tmchk timeout key, pushes the request, blpops the response (default 60s), and re-raises typed errors (pyredisrpc.py:126-167). __getattr__ makes calls look like methods (client.compareFaces(a,b)) (pyredisrpc.py:169-173). A built-in pingpong method exists for liveness (pyredisrpc.py:41). HTTP resources hold a module-level client, e.g. faceRpcClient = RedisRpcClient("face", config["redis"]) (server/http/resources/face_compare.py:7).

Config — server/cfg.py

Loaded at import time by every entrypoint. Merges (via jsonmerge) config/<PYTHON_ENV>.jsonconfig/jsonschemas.json → optional config/scaling_presets/<SCALING_PRESET>.json (docker only) → config/local.json (server/cfg.py:12-29). Hard requirements that raise RuntimeError on failure: PYTHON_ENV ∈ {dev, docker} (:9-10); requiredEnvVersion present (:33-34); env var ENV_VERSION present and == requiredEnvVersion (:36-42). Loads DOCUMENT_CLASS_ID_MAPPING from data/card_detector_classification_classId_mapping.json and derives allowedDocumentIds, optionally filtered by a documentWhitelist config (raises if a whitelisted doc is unknown) (:47-58). Configures loguru from config.logger and validates every HTTP/WebSocket JSON schema against Draft 7 (:68-96).

Image store — server/appcache.py

Redis-keyed store with prefixes raw-image:, numpy-image:, metadata:, audio-frame: (appcache.py:18-21). NumPy images are stored as a packed header >IIB (height, width, channel-order enum) + raw bytes, default TTL 60s (appcache.py:84-146). getNumPyImage lazily decodes a raw image via imageio if no numpy form exists, normalizes channel order, strips alpha (appcache.py:88-129). ChannelOrder (GRAYSCALE/RGB24/BGR24) + NumPyImageWrapper centralize all cv2 color conversions (appcache.py:23-81). Audio frames are packed as layout(1) + format(15) + sample_rate(3) + payload for av.AudioFrame round-tripping (appcache.py:193-226). Metadata uses pickle (appcache.py:184-191).

ML inference core — ml/utils.py, ml/ml_model_runner.py

createInferenceSession picks ONNXRuntime execution providers by INFERENCE_DEVICE_MODE (cpu/gpu/force_gpu, default gpu with CPU fallback) and isGpuAvailable() (shells out to nvidia-smi -L) (ml/utils.py:11-88). checkGpuEnabled(config, key) forces CPU mode when config.scaling.<key>.gpuEnabled == false — called at the very top of each model worker (e.g. app_face.py:14) before models load (ml/utils.py:90-92). runSession uses IO binding on GPU. MlModelRunner (abstract) wraps a session and runs a random-input warmup on init (ml/ml_model_runner.py:10-44). Per-model packages live in ml/<name>/ with a main.py (run) façade.

Documents — server/documents/

17 document template classes (HunAo03001, HunBo03004Back/Front, …, SrbBo01001Front) registered in DOCUMENTS, sorted by class id, exposing getName() / getClassId() and ROI/MRZ geometry; lookups via getDocumentByClassId / getDocumentByName raise DocumentNotFound (server/documents/__init__.py:21-64). Used by OCR/MRZ/recognition engines.

HTTP resources & WS tasks

23 Falcon resource classes under server/http/resources/ (one per route; 24 *.py files incl. __init__.py), most decorated with @jsonschema.validate(req_schema=…, resp_schema=…) from config["jsonschemas"]["http"][…] and delegating to an RPC client (pattern in face_compare.py:10-30). 14 streaming task types in server/websocket/task/__init__.py:59-74 (action, barcode, document, face, holo, holoImage, holoV2, liveness, livenessV2, mrz, sharpness, streamPlayer, speechDetection, padDetection); selected at WS init by taskType in the init message (validated against jsonschemas.websocket.init-message, app_websocket.py:58-62). 16 server/cv/*_engine.py modules (+ 3 holo/ utilities) orchestrate the actual CV pipelines.


7. Configuration

Config files (config/)

  • config/dev.json / config/docker.json — per-env config selected by PYTHON_ENV. Both set requiredEnvVersion: 8, Redis over unix socket /var/run/redis/redis-server.sock db 0, supported MIME image/png|image/jpeg, scaling.* process/worker counts, webrtc.peerConnectionConfig.iceServers: [], version: "4.9.1" (config/docker.json:1-55, config/dev.json:1-66). dev.json additionally enables asyncio.debug and EasyOCR rs_cyrillic/rs_latin boot, and points streamPlayerDir at a test-resources path.
  • config/jsonschemas.json — single top-level key jsonschemas with definitions, http, websocket (verified). Contains 42 HTTP schemas (request/response pairs for image-upload, mrz, face-detect, reference-face-extract, face-gender-age, document-ocr, document-recognition, document-warp v1/v2/v3, card-warp, card-integrity-check, face-compare, face-draw, image-download, sharpness, barcode, barcode-detect, ocr, background-mask, kaptcha-decoder, status) plus websocket schemas (e.g. init-message). Each is merged with definitions and validated as Draft 7 at boot (server/cfg.py:73-96).
  • config/local.jsonnot present in repo; it is the last merge layer and is optional (server/cfg.py:20, server/cfg.py:30-31 swallow FileNotFoundError). This is the intended place for per-deployment overrides (e.g. scaling, GPU mode) per Readme.md:109-126.
  • config/scaling_presets/50rt_25non_rt.json — the only preset; selected via SCALING_PRESET env var (docker only). Tuned for an Nvidia L40S serving 50 RT + 25 non-RT clients (Readme.md:137-153, file read). Sets large process/worker counts (e.g. websocket.processes: 75, face.workers: 20) and forces onnx/detectron2 to CPU.

Environment variables (verified in code)

VarEffectSource
PYTHON_ENVdev/docker; selects config file; requiredserver/cfg.py:9-15
ENV_VERSIONmust equal config requiredEnvVersion (=8) or boot failsserver/cfg.py:36-42
INFERENCE_DEVICE_MODEcpu/gpu/force_gpu ONNX EP selectionml/utils.py:34, Readme.md:43-47
SCALING_PRESETdocker: extra config layer name from scaling_presets/server/cfg.py:17-18
NUM_<KEY>_PROCESSESper-program numprocs/uWSGI --processes; generated by load_config_into_env_file.py from config.scaling.<key>.processes for keys face/ocr/textDetector/cardDetector/mrz/detectron2/websocket/httpsetup/load_config_into_env_file.py:13-39, supervisor_vuer_cv_docker.conf:30,54,75,…
DEV_DOMAINdev: derives config.host = https://cv-<DEV_DOMAIN>server/cfg.py:44-45
APP_HOMEbase dir for nginx template rendersetup/generate_nginx_conf.py:7,17
COVERAGE_PROCESS_STARTpath to .coveragerc; enables per-process line coverageapp_http.py:6-9, tests/runcoverage.sh:222

Network ports (from configs)

  • nginx public listener 4080 (docker template) — static web/ root, /api/*→uWSGI, /ws→WS upstream (nginx_vuer_cv_docker.conf.j2:10-41).
  • uWSGI socket 40081 (uwsgi_vuer_cv_docker.ini:23); stats HTTP 9191 (:39-40).
  • WebSocket workers 40082 + worker with nginx max_conns=1 per upstream (app_websocket.py:114, nginx_vuer_cv_docker.conf.j2:5).
  • CI/dev fronting: upstream vuer-cv at 127.0.0.1:40080, TLS 8443 (.travis.yml:46-48).

uWSGI hardening: harakiri=60, max-requests=1000, max-worker-lifetime=3600, reload-on-rss=2048 MB, buffer-size=65535, limit-post=0 (uwsgi_vuer_cv_docker.ini:11-37).


8. Tests

  • Framework: pytest (+ pytest-xdist, pytest-xdist-load-testing, pytest-xdist-rate-limit, pytest-timeout, coverage, requests) — requirements/dev-requirements.in:12-21. Markers: perftest, coverage (tests/pytest.toml).
  • Location: tests/unit_test.py, api_test.py, error_test.py, cli_test.py, perftest_runner.py; helpers in tests/utils/ (http_client.py, ws_client.py, rpc_ping_server.py, frame_swap_videotrack.py); load tests in tests/load_test/ (load_test.py, conftest.py); shared conftest.py.
  • Coverage scope/omit: .coveragerc — sources server/**, omits bin/*, tests/*, packages/*, OpenCV/PyTorch auto-generated files; concurrency = multiprocessing,thread, parallel = True (so each worker process dumps its own .coverage.*, later coverage combined).
  • How to run (the canonical path): tests/runcoverage.sh (run inside the container; -l/--local stops/starts supervisor programs around the run). It: cleans prior coverage; runs Trivy repo vuln scan over requirements.*.txt (fails build if any unignored vuln, .trivyignore is the allowlist; runcoverage.sh:182-203); coverage run -m pytest tests/unit_test.py; boots “blank” app_http/app_websocket under coverage to capture import/boot lines (:209-219); sets COVERAGE_PROCESS_START; then start-services (launches all app_* under coverage run) and waits until every RPC queue answers ping via tests/utils/rpc_ping_server.py (:108-139); runs api_test.py, error_test.py, and the coverage-marked subset of cli_test.py; finally coverage combinehtml/xml/json, printing total percent (:279-286).
  • CI: Travis (.travis.yml). Pulls the prebuilt vuer_cv_dev:latest image, mounts this repo + cloned cert/test_resources, runs prepare.sh + supervisord + pip install reqs + tests/runcoverage.sh, pushes coverage.xml to a results repo, then runs SonarCloud scan (.travis.yml:42-80). Sonar config: sonar-project.properties.

Running tests requires external repos not in this clone: TechTeamer/cert, TechTeamer/test_resources, TechTeamer/travis-ci-results (.travis.yml:37-39) and the prebuilt image. There is no standalone "run unit tests on a laptop" path documented; tests assume the container + Redis + all model workers.


9. Dependencies on other FaceKom services

No outbound calls to other FaceKom services are evidenced in this repo's source. vuer_cv is self-contained at runtime:

  • Redis — co-located, accessed via unix socket /var/run/redis/redis-server.sock (config/docker.json:3-6), launched by supervisord in the same container (supervisor_vuer_cv_docker.conf:20-26). Used purely as the internal RPC bus + image/frame cache. No external Redis host/port configured.
  • No RabbitMQ — searched dependencies/config; none. (Contrast with queue-driven FaceKom services; vuer_cv uses Redis-list RPC instead.)
  • No outbound HTTP/DB clientsrequirements.in has no SQL/Mongo/amqp driver; config.host is only a self-referential URL for dev (server/cfg.py:44-45).
  • Inbound only: it is fronted by Nginx (in-container) and reached by upstream FaceKom components over /api/* (REST) and /ws (WebSocket/WebRTC). The actual callers live in other repos — see architecture-overview.

10. Verified gotchas

Env-version lock. Boot aborts unless the ENV_VERSION env var (baked into the image) equals requiredEnvVersion: 8 in the config. Bumping the image base without bumping config (or vice-versa) hard-fails every process (server/cfg.py:36-42).

local.json overrides everything. It is the last jsonmerge layer and is git-ignored/absent here. A stray config/local.json on a host silently changes scaling, GPU mode, document whitelist, etc. (server/cfg.py:20).

Generated nginx conf is clobbered on start. Edit the .j2 template, not nginx_vuer_cv_$ENV.conf (Readme.md:160-164, prepare.sh:12).

OCR worker can't be multi-threaded. app_ocr.py ignores worker scaling due to a ThreadPoolExecutor/interpreter-shutdown bug (app_ocr.py:91-92).

GPU disable must be set before model import. checkGpuEnabled mutates INFERENCE_DEVICE_MODE and is intentionally the first call in each worker, before any ml.* import — moving model imports above it breaks CPU forcing (app_face.py:14-16, ml/utils.py:90-92).

OpenCV 4.9+ writeable-array check. drawFace must .copy() the cached image before cv2.drawMarker, since cached numpy arrays are non-writeable and newer OpenCV enforces it (previously a potential segfault) (app_face.py:124-131).

build.ignore lists what is stripped from the production runtime (dev config, tests, metrics/CSVs/PNGs in data/, dev .conf/.ini, markdown, pylint/sonar files) — a manifest of "dev-only" artifacts, not a .dockerignore (build.ignore).

Per-model device table. Which models can use GPU vs are CPU-forced is documented in Readme.md:166-192 (e.g. Silero VAD, EasyOCR, Detectron2, SVMs, Tesseract MRZ are CPU-only).


Unverified / gaps

  • Surveyed structurally, not line-by-line (listed + spot-sampled, not every file read): all 16 server/cv/*_engine.py and the 3 server/cv/holo/*; all 24 server/http/resources/*.py (23 resource classes + __init__.py; read only face_compare.py as the representative pattern); all 14 server/websocket/task/* and the processor//framestore/ trees (read only the task/__init__.py registry); all 17 server/documents/hun_*/srb_* classes (read only the registry __init__.py); every ml/<model>/main.py + model class (read only ml/utils.py, ml/ml_model_runner.py); all server/utils/*; the bin/*_testing.py bodies (read argparse descriptions + the 4 non-argparse utility scripts fully); the entire web/manualtest/** static front-end; tests/* bodies (behavior derived from runcoverage.sh, not from reading each test); packages/passporteye/** internals (vendored fork — manifest/role only).
  • Python version is not pinned in-repo (no python_requires/engines); ≥3.10 inferred from union-type syntax in source. Exact interpreter is set by the external image.
  • Dockerfile / image build lives in a different repo (not present here); image identity taken from .travis.yml.
  • data/** weights are LFS pointers — model file sizes/oids recorded from pointer headers, contents not inspected.
  • config/local.json and config/jsonschemaswebsocket schema names not enumerated (the websocket key exists and is validated; only init-message is referenced from code, app_websocket.py:58).

Sources

  • Root: Readme.md, changelog.md, docker_entrypoint.sh, prepare.sh, .travis.yml, .gitattributes, .coveragerc, .trivyignore, build.ignore, sonar-project.properties
  • Entrypoints: app_http.py, app_websocket.py, app_face.py, app_card_detector.py, app_ocr.py, app_text_detector.py, app_detectron2.py, app_mrz.py, app_pad.py, app_onnx.py
  • server/: server/cfg.py, server/appcache.py, server/rpc/pyredisrpc.py, server/http/resources/face_compare.py, server/documents/__init__.py, server/websocket/task/__init__.py
  • ml/: ml/utils.py, ml/ml_model_runner.py
  • Config: config/dev.json, config/docker.json, config/jsonschemas.json (structure + http schema names), config/scaling_presets/50rt_25non_rt.json
  • Requirements: requirements/requirements.in, requirements/requirements-2.in, requirements/dev-requirements.in, requirements/compile.sh, requirements/install.sh
  • Setup/proc: setup/load_config_into_env_file.py, setup/generate_nginx_conf.py, supervisor_vuer_cv_docker.conf, uwsgi_vuer_cv_docker.ini, nginx_vuer_cv_docker.conf.j2
  • bin: bin/utils.py, bin/healthcheck.py, bin/check_env_version.py, bin/test_case.py (+ argparse description= of all bin/*_testing.py / *_evaluation.py / visualize_*)
  • Tests: tests/pytest.toml, tests/runcoverage.sh
  • Tree listing via find (full repo, excl. .git)
  • Git: git -C … branch -a, git -C … log (HEAD 24f66dc, PR #418 “bump-version-to-4.9.1”)