Files
Behavision/shared/cameraMakes.js
Suriyakumarvijayanayagam dad04e8cda Behavision: face recognition for retail, edge to head office
Five components that ship as one product:

- behavision/  the recognition engine. RTSP ingest, YuNet detection, IoU
               tracking, ArcFace embeddings, a FAISS/SQLite gallery, and a
               FastAPI dashboard. Identity is decided once per TRACK from an
               average of at least three embeddings, never per frame.
- agent/       the Go edge agent: supervises the engine, holds a durable
               spool, and drains it to MQTT. Nothing is acked before the
               broker confirms.
- desktop/     the shop PC application (Wails + React + tray).
- server/      the cloud API, MQTT consumer, reports and assistant.
- web/         platform.loyaly.ai, the head-office app, embedded in the
               server binary.

The gallery stores 512-float embeddings and timestamps - no images unless
`app.store_faces` is switched on. Those embeddings are biometric personal
data under GDPR and India's DPDP: template inversion reconstructs a
recognisable face from an ArcFace vector, so data/behavision.db is treated
as a biometric database and DELETE /api/visitors/{id} is a real erasure.

CLAUDE.md carries the reasoning behind every non-obvious decision here,
including the ones that were measured and the ones that were wrong first.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HViLj9gYNRtSr7YVZmW5sn
2026-09-04 11:14:18 +05:30

82 lines
2.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// The stream path for the common camera makes.
//
// Imported by BOTH user interfaces - the head-office web app and the shop PC's
// desktop app - and kept here rather than copied into each because a make that
// is right in one and stale in the other is worse than not offering the list at
// all: an installer trusts a filled-in field.
//
// This is the single biggest obstacle for somebody setting up their first
// camera: the address and the password are on a label or in the installer's
// notes, but the RTSP *path* is not written anywhere a shop owner would look.
// It is model-specific, undiscoverable, and getting it wrong produces "could
// not open stream", which reads like a password problem and is not.
//
// Picking a make fills it in. The field stays editable, because these are
// conventions rather than guarantees and an installer who knows better must be
// able to overrule us.
export const MAKES = [
{
id: 'hikvision',
label: 'Hikvision',
path: '/Streaming/Channels/101',
note: 'Channel 1, main stream. Use /Streaming/Channels/102 for the lower-quality sub stream.',
},
{
id: 'dahua',
label: 'Dahua',
path: '/cam/realmonitor?channel=1&subtype=0',
note: 'Channel 1, main stream. subtype=1 is the sub stream.',
},
{
// Dahua hardware under another name, and very common in Indian retail.
id: 'cpplus',
label: 'CP Plus',
path: '/cam/realmonitor?channel=1&subtype=0',
note: 'CP Plus cameras use the Dahua stream path.',
},
{
id: 'uniview',
label: 'Uniview',
path: '/media/video1',
note: 'Some older Uniview models use /video1 instead.',
},
{
id: 'tplink',
label: 'TP-Link / Tapo',
path: '/stream1',
note: 'Tapo cameras need a separate camera account created in the Tapo app — your Tapo login will not work.',
},
{
id: 'reolink',
label: 'Reolink',
path: '/h264Preview_01_main',
note: 'Use /h264Preview_01_sub for the lower-quality stream.',
},
{
id: 'amcrest',
label: 'Amcrest',
path: '/cam/realmonitor?channel=1&subtype=0',
note: 'Amcrest cameras use the Dahua stream path.',
},
{
id: 'axis',
label: 'Axis',
path: '/axis-media/media.amp',
note: '',
},
{
id: 'onvif',
label: 'Other (ONVIF)',
path: '/onvif1',
note: 'Many generic cameras answer here. If it does not work, look for “RTSP” in the camera’s own app.',
},
{
id: 'manual',
label: 'I know the path',
path: '',
note: '',
},
]
export const makeById = (id) => MAKES.find(m => m.id === id) || MAKES[MAKES.length - 1]