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/*.pklmodel weights present here are LFS pointer files, not real binaries (verified:data/ghostnetv2_w1_3_s2.onnxbeginsversion https://git-lfs.github.com/spec/v1,oid sha256:…,size 27038712). They were never opened.
No
Dockerfileexists in this repo (searched: none found). The runtime image is prebuilt and pulled from a registry — CI usesharbor.techteamer.com/facekom-devel/vuer_cv_dev:latest(.travis.yml:42,75). The Python source mounts into/workspace/vuer_cvinside 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
| Aspect | Value | Source |
|---|---|---|
| Language | Python (uses 3.10+ syntax: `str | None, walrus, match`-free) |
| HTTP framework | Falcon 4.2.0 + falcon-multipart | requirements/requirements.in:17,19, app_http.py:32-33 |
| WSGI server | uWSGI 2.0.31 | requirements/requirements.in:15, uwsgi_vuer_cv_docker.ini |
| WebSocket | websockets 16.0, uvloop 0.22.1 | requirements/requirements.in:31,16, app_websocket.py |
| WebRTC | aiortc 1.14.0, av 16.1.0, pyee | requirements/requirements.in:32,30,33 |
| RPC bus | Redis 7.4.0 (redis-py) over unix socket | requirements/requirements.in:16, config/docker.json:3-6 |
| ML runtime | onnxruntime-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 libs | opencv-python-headless 4.13, Pillow 12.2, numpy 2.4.5, scipy, shapely, scikit-image, imageio | requirements/requirements.in |
| MRZ | local vendored PassportEye + pytesseract | packages/passporteye/, requirements/requirements-2.in:6 |
| Process mgr | supervisord | supervisor_vuer_cv_docker.conf |
| Reverse proxy | nginx (templated via Jinja2) | nginx_vuer_cv_docker.conf.j2, setup/generate_nginx_conf.py |
| Logging | loguru | everywhere |
| Package manager | pip + pip-tools (pip-compile) | requirements/compile.sh, requirements/install.sh |
| Config merge | jsonmerge + jsonschema (Draft 7) | server/cfg.py:5,79 |
requirements.indoes not pin Python itself, and there is noengines/python_requiresfield. 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).
setuptoolsis deliberately not inrequirements.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.
| Entrypoint | Role | RPC queue / port | Source |
|---|---|---|---|
app_http.py | Falcon WSGI app (application global), 24 REST routes (24 add_route( calls, app_http.py:66-89) | uWSGI socket 127.0.0.1:40081 | app_http.py:63-97, uwsgi_vuer_cv_docker.ini:23 |
app_websocket.py | asyncio WebSocket server, dispatches taskType→CV task | listens 40082 + worker | app_websocket.py:108-115 |
app_face.py | face detect/encode/compare/landmark/gender-age/sunglasses | RPC face | app_face.py:170-188 |
app_card_detector.py | card warp/classify/integrity | RPC cardDetector | app_card_detector.py:65-73 |
app_ocr.py | kaptcha + generic + document OCR | RPC ocr | app_ocr.py:83-89 |
app_text_detector.py | FAST text detection | RPC textDetector | app_text_detector.py:50-54 |
app_detectron2.py | barcode detection (Detectron2) | RPC detectron2 | app_detectron2.py:36-42 |
app_mrz.py | MRZ reading (Passporteye/Tesseract) | RPC mrz | app_mrz.py:168-175 |
app_pad.py | presentation-attack + deepfake detection | RPC pad | app_pad.py:41-48 |
app_onnx.py | background masking (MODNet) + speech detection (VAD) | RPC onnx | app_onnx.py:40-45 |
app_onnx.pyandapp_pad.pyalways runnumprocs=1(hard-coded insupervisor_vuer_cv_docker.conf:96,201); all others scale viaENV_NUM_*_PROCESSESenv vars produced from config (see §7).
app_ocr.pycannot run multiple in-process worker threads — comment atapp_ocr.py:91-92: a Python bug conflicts withDocumentOcrEngine'sThreadPoolExecutorcausing "cannot schedule new futures after interpreter shutdown". It always runs a singlerpcServer.run().
Start sequence (production / PYTHON_ENV=docker)
docker_entrypoint.sh→source ./prepare.shthensupervisord -n -c /etc/supervisor/supervisord.conf(docker_entrypoint.sh:5-7).prepare.sh(prepare.sh:6-12):python setup/load_config_into_env_file.py <tmpfile>→ writesNUM_<KEY>_PROCESSESenv vars fromconfig.scaling.*.processes.sourcethat tmpfile into the environment.python setup/generate_nginx_conf.py nginx_vuer_cv_$PYTHON_ENV.conf→ renders the.j2template withserver_count = NUM_WEBSOCKET_PROCESSES.
supervisordlaunches programs (supervisor_vuer_cv_docker.conf):nginx,redis,vuer_cv(uWSGI runningapp_http.pywith--processes $NUM_HTTP_PROCESSES), andnumprocs-scaledvuer_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.shoverwritesnginx_vuer_cv_$ENV.confon every container start (Readme.md:160-164). Put custom Nginx changes in a copy of the.j2template, 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)
| Script | What it does | Source |
|---|---|---|
docker_entrypoint.sh | container PID 1: source prepare.sh, exec supervisord -n | docker_entrypoint.sh |
prepare.sh | generate scaling env vars + render nginx conf (see above) | prepare.sh |
requirements/compile.sh | dev-only (exit 1 if PYTHON_ENV != dev): pip-compile each requirements*.in (+ optional --upgrade) | requirements/compile.sh:9-21 |
requirements/install.sh | dev: pip install -r all three .txt; non-dev: same with --no-cache-dir (no dev reqs) | requirements/install.sh:7-14 |
tests/runcoverage.sh | full CI test+coverage+Trivy pipeline (see §8) | tests/runcoverage.sh |
bin/benchmark/run.sh | benchmark runner (under bin/benchmark/) | bin/benchmark/run.sh |
4. Top-level structure
| Path | Purpose | Verified |
|---|---|---|
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, utils | listed + sampled |
server/cfg.py | Config loader/validator (merge JSONs, AJV-style schema checks, env-version gate) | read |
server/appcache.py | Redis-backed image/audio/metadata store; NumPyImageWrapper, channel-order conversion | read |
server/rpc/pyredisrpc.py | RedisRpcServer / 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__.py | listed + sampled face_compare.py |
server/http/exeption_handler.py, server/utils/http_not_found.py | global error + 404 sink | referenced 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.py | listed |
server/documents/ | 17 per-document ROI/template classes (hun_*, srb_*) + registry __init__.py | listed + read __init__.py |
server/websocket/ | WS connection, stream handler, processor/, framestore/, task/ | listed |
server/websocket/task/ | 14 streaming CV task types + taskMap registry | read __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.py | listed + 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.md | listed |
config/ | dev.json, docker.json, jsonschemas.json, scaling_presets/ | read all |
requirements/ | *.in source + *.txt pinned + compile.sh / install.sh | read |
setup/ | load_config_into_env_file.py, generate_nginx_conf.py | read both |
packages/passporteye/ | vendored MRZ library (first-party fork; installed via requirements-2.in) | listed + manifest |
tests/ | pytest suites + utils/ clients + load_test/ + runcoverage.sh | read 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 JSON | listed (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.md | read most |
*.ini / *.j2 / *.conf | uWSGI 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).
| Script | Description / role | Source |
|---|---|---|
bin/utils.py | shared helpers: prettyJson, loadFromJson, saveToJson, saveDebugImage, saveBenchmark, writeCsv (writes to /workspace/vuer_cv/data/benchmarks/) | read fully |
bin/test_case.py | base TestCase scaffolding (imports ArgumentParser) used by the testing scripts | bin/test_case.py:1 |
bin/healthcheck.py | calls StatusEngine.getServerStatus(level), prints JSON, exit(1) if status != green; `-l/—level basic | medium |
bin/check_env_version.py | imports 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.py | standalone 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.py | visualize face ROIs (argparse desc reused: “Test hologram detection with prerecorded input.”) | argparse |
bin/visualize_holo_rois.py | visualize 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 one | argparse + comment |
bin/benchmark/run.sh | benchmark suite runner | listed |
bin/benchmark/v1-*.py, v3-document-recognize.py | per-feature benchmark scripts (barcode-detection, document-ocr, face-compare, face-detect, mrz, document-recognize) | listed |
bin/benchmark/benchmarking.md | benchmark docs | listed |
Several
visualize_*/*_testingscripts share copy-pasted argparse descriptions (e.g.visualize_face_rois.pysays "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 ping→pong 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>.json → config/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 byPYTHON_ENV. Both setrequiredEnvVersion: 8, Redis over unix socket/var/run/redis/redis-server.sockdb 0, supported MIMEimage/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.jsonadditionally enablesasyncio.debugand EasyOCR rs_cyrillic/rs_latin boot, and pointsstreamPlayerDirat a test-resources path.config/jsonschemas.json— single top-level keyjsonschemaswithdefinitions,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 withdefinitionsand validated as Draft 7 at boot (server/cfg.py:73-96).config/local.json— not present in repo; it is the last merge layer and is optional (server/cfg.py:20,server/cfg.py:30-31swallowFileNotFoundError). This is the intended place for per-deployment overrides (e.g.scaling, GPU mode) perReadme.md:109-126.config/scaling_presets/50rt_25non_rt.json— the only preset; selected viaSCALING_PRESETenv 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 forcesonnx/detectron2to CPU.
Environment variables (verified in code)
| Var | Effect | Source |
|---|---|---|
PYTHON_ENV | dev/docker; selects config file; required | server/cfg.py:9-15 |
ENV_VERSION | must equal config requiredEnvVersion (=8) or boot fails | server/cfg.py:36-42 |
INFERENCE_DEVICE_MODE | cpu/gpu/force_gpu ONNX EP selection | ml/utils.py:34, Readme.md:43-47 |
SCALING_PRESET | docker: extra config layer name from scaling_presets/ | server/cfg.py:17-18 |
NUM_<KEY>_PROCESSES | per-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/http | setup/load_config_into_env_file.py:13-39, supervisor_vuer_cv_docker.conf:30,54,75,… |
DEV_DOMAIN | dev: derives config.host = https://cv-<DEV_DOMAIN> | server/cfg.py:44-45 |
APP_HOME | base dir for nginx template render | setup/generate_nginx_conf.py:7,17 |
COVERAGE_PROCESS_START | path to .coveragerc; enables per-process line coverage | app_http.py:6-9, tests/runcoverage.sh:222 |
Network ports (from configs)
- nginx public listener
4080(docker template) — staticweb/root,/api/*→uWSGI,/ws→WS upstream (nginx_vuer_cv_docker.conf.j2:10-41). - uWSGI socket
40081(uwsgi_vuer_cv_docker.ini:23); stats HTTP9191(:39-40). - WebSocket workers
40082 + workerwith nginxmax_conns=1per upstream (app_websocket.py:114,nginx_vuer_cv_docker.conf.j2:5). - CI/dev fronting: upstream
vuer-cvat127.0.0.1:40080, TLS8443(.travis.yml:46-48).
uWSGI hardening:
harakiri=60,max-requests=1000,max-worker-lifetime=3600,reload-on-rss=2048MB,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 intests/utils/(http_client.py,ws_client.py,rpc_ping_server.py,frame_swap_videotrack.py); load tests intests/load_test/(load_test.py,conftest.py); sharedconftest.py. - Coverage scope/omit:
.coveragerc— sourcesserver/**, omitsbin/*,tests/*,packages/*, OpenCV/PyTorch auto-generated files;concurrency = multiprocessing,thread,parallel = True(so each worker process dumps its own.coverage.*, latercoverage combined). - How to run (the canonical path):
tests/runcoverage.sh(run inside the container;-l/--localstops/starts supervisor programs around the run). It: cleans prior coverage; runs Trivy repo vuln scan overrequirements.*.txt(fails build if any unignored vuln,.trivyignoreis the allowlist;runcoverage.sh:182-203);coverage run -m pytest tests/unit_test.py; boots “blank”app_http/app_websocketunder coverage to capture import/boot lines (:209-219); setsCOVERAGE_PROCESS_START; thenstart-services(launches allapp_*undercoverage run) and waits until every RPC queue answerspingviatests/utils/rpc_ping_server.py(:108-139); runsapi_test.py,error_test.py, and thecoverage-marked subset ofcli_test.py; finallycoverage combine→html/xml/json, printing total percent (:279-286). - CI: Travis (
.travis.yml). Pulls the prebuiltvuer_cv_dev:latestimage, mounts this repo + clonedcert/test_resources, runsprepare.sh+ supervisord +pip installreqs +tests/runcoverage.sh, pushescoverage.xmlto 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 clients —
requirements.inhas no SQL/Mongo/amqp driver;config.hostis 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_VERSIONenv var (baked into the image) equalsrequiredEnvVersion: 8in the config. Bumping the image base without bumping config (or vice-versa) hard-fails every process (server/cfg.py:36-42).
local.jsonoverrides everything. It is the lastjsonmergelayer and is git-ignored/absent here. A strayconfig/local.jsonon a host silently changes scaling, GPU mode, document whitelist, etc. (server/cfg.py:20).
Generated nginx conf is clobbered on start. Edit the
.j2template, notnginx_vuer_cv_$ENV.conf(Readme.md:160-164,prepare.sh:12).
OCR worker can't be multi-threaded.
app_ocr.pyignores worker scaling due to aThreadPoolExecutor/interpreter-shutdown bug (app_ocr.py:91-92).
GPU disable must be set before model import.
checkGpuEnabledmutatesINFERENCE_DEVICE_MODEand is intentionally the first call in each worker, before anyml.*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.
drawFacemust.copy()the cached image beforecv2.drawMarker, since cached numpy arrays are non-writeable and newer OpenCV enforces it (previously a potential segfault) (app_face.py:124-131).
build.ignorelists what is stripped from the production runtime (dev config, tests, metrics/CSVs/PNGs indata/, 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.pyand the 3server/cv/holo/*; all 24server/http/resources/*.py(23 resource classes +__init__.py; read onlyface_compare.pyas the representative pattern); all 14server/websocket/task/*and theprocessor//framestore/trees (read only thetask/__init__.pyregistry); all 17server/documents/hun_*/srb_*classes (read only the registry__init__.py); everyml/<model>/main.py+ model class (read onlyml/utils.py,ml/ml_model_runner.py); allserver/utils/*; thebin/*_testing.pybodies (read argparse descriptions + the 4 non-argparse utility scripts fully); the entireweb/manualtest/**static front-end;tests/*bodies (behavior derived fromruncoverage.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.jsonandconfig/jsonschemas’websocketschema names not enumerated (thewebsocketkey exists and is validated; onlyinit-messageis 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__.pyml/: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(+ argparsedescription=of allbin/*_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(HEAD24f66dc, PR #418 “bump-version-to-4.9.1”)