Files
Behavision/installer/behavision.iss
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

163 lines
7.2 KiB
Plaintext

; Behavision installer (Inno Setup 6).
;
; Built by installer\build.ps1, which stages dist\Behavision first. Compile it
; by hand with:
; ISCC.exe /DMyAppVersion=0.1.0 installer\behavision.iss
;
; Three decisions worth reading before changing anything here:
;
; 1. ADMIN AT INSTALL TIME, NEVER AT RUN TIME. The files go under Program
; Files, so installing needs elevation. Running does not: the app is a
; normal user-session process that spawns the engine as a child, which is
; also why it can draw a tray icon at all - a Windows service runs in
; session 0 and cannot.
;
; 2. NO MODELS IN THE PACKAGE. They are ~200 MB and `setup-models` downloads
; them resumably into the state root on first run. Bundling them would
; quadruple this file and force a re-sign for a model change.
;
; 3. NOTHING WRITABLE UNDER Program Files. The database, logs, camera list,
; downloaded models and agent config all live in %PROGRAMDATA%\Behavision,
; which is what makes an upgrade a file copy rather than a migration. That
; split is behavision/paths.py and agent/pkg/paths, and this file must not
; contradict it.
#define MyAppName "Behavision"
#ifndef MyAppVersion
#define MyAppVersion "0.1.0"
#endif
#define MyAppPublisher "Loyaly"
#define MyAppURL "https://platform.loyaly.ai"
#define MyAppExeName "Behavision.exe"
[Setup]
AppId={{7C4B9E2A-3F51-4C86-9D0A-B1E7A2F65D11}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
DefaultDirName={autopf}\{#MyAppName}
DefaultGroupName={#MyAppName}
DisableProgramGroupPage=yes
OutputDir=..\dist
OutputBaseFilename=Behavision-Setup-{#MyAppVersion}
Compression=lzma2/max
SolidCompression=yes
WizardStyle=modern
; Admin, because Program Files is. See decision 1 above.
PrivilegesRequired=admin
ArchitecturesAllowed=x64compatible
ArchitecturesInstallIn64BitMode=x64compatible
UninstallDisplayIcon={app}\{#MyAppExeName}
; The engine folder alone is ~400 MB unpacked; saying so up front beats a
; wizard that stops halfway on a small shop PC.
ExtraDiskSpaceRequired=450000000
; Ask Windows' Restart Manager to close a running copy instead of writing DLLs
; underneath it. The engine holds the SQLite WAL and the camera, so a half
; replaced install fails on the NEXT start - long after anyone would connect
; the two events. RestartApplications=no because the [Run] section starts the
; app again itself, and twice is one process too many for one webcam.
CloseApplications=yes
RestartApplications=no
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Tasks]
Name: "desktopicon"; Description: "Create a &desktop shortcut"; GroupDescription: "Shortcuts:"
; Ticked by default: the product is meaningless if it is not watching. A shop
; PC reboots after a power cut at 3am with nobody there to open anything.
Name: "startup"; Description: "Start Behavision when this PC starts"; GroupDescription: "Startup:"
[Files]
Source: "..\dist\Behavision\Behavision.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\dist\Behavision\behavision-agent.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\dist\Behavision\engine\*"; DestDir: "{app}\engine"; Flags: ignoreversion recursesubdirs createallsubdirs
; ~2 MB bootstrapper, downloaded at build time by build.ps1. The app is a
; WebView2 window; without the runtime it opens BLANK - not an error, just an
; empty white rectangle, which is the single worst failure mode to hand a shop.
; Present on Windows 11 and recent Windows 10, absent on plenty of older
; machines, and a shop PC is exactly where an older machine lives.
Source: "vendor\MicrosoftEdgeWebview2Setup.exe"; DestDir: "{tmp}"; \
Flags: deleteafterinstall; Check: WebView2Missing
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
; Per-user, not HKLM\Run: the app draws a tray icon and a window, so it has to
; start in an interactive session. A machine-wide entry would try before anyone
; has logged in.
Name: "{userstartup}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: startup
; Named in the installer's own text when somebody skips the download, so it has
; to exist. Console window on purpose: it is a 200 MB download with a progress
; line, and a silent one looks like nothing happened.
Name: "{group}\Download models"; Filename: "{app}\engine\behavision.exe"; \
Parameters: "setup-models"; Comment: "Download the face recognition models"
Name: "{group}\Where is my data"; Filename: "{app}\engine\behavision.exe"; \
Parameters: "paths"; Comment: "Print the installed layout"
[Dirs]
; Created here so a first run does not have to, and ACLed to Administrators
; plus the installing user rather than Everyone: it holds face templates, which
; are biometric personal data, and the engine's generated API password.
Name: "{commonappdata}\Behavision"; Permissions: admins-full users-modify
[Run]
Filename: "{tmp}\MicrosoftEdgeWebview2Setup.exe"; Parameters: "/silent /install"; \
StatusMsg: "Installing Microsoft Edge WebView2 (required to show the app)..."; \
Flags: waituntilterminated; Check: WebView2Missing
; ~200 MB over the network, so it is offered rather than forced, and it is
; resumable: a killed download leaves a .part file and the next run continues.
Filename: "{app}\engine\behavision.exe"; Parameters: "setup-models"; \
StatusMsg: "Downloading face recognition models (about 200 MB)..."; \
Flags: runhidden waituntilterminated; Check: WantModels
Filename: "{app}\{#MyAppExeName}"; Description: "Start {#MyAppName} now"; \
Flags: nowait postinstall skipifsilent
[UninstallDelete]
; The unpacked engine writes nothing here, but PyInstaller leaves stray
; __pycache__ directories that would keep {app} alive after an uninstall.
Type: filesandordirs; Name: "{app}\engine"
[Code]
var
ModelsPage: TInputOptionWizardPage;
procedure InitializeWizard;
begin
ModelsPage := CreateInputOptionPage(wpSelectTasks,
'Face recognition models',
'Behavision needs about 200 MB of model files to recognise faces.',
'These are downloaded once. If this PC has no internet connection now, ' +
'skip this and run "Download models" from the Start menu later - the app ' +
'will not recognise anyone until they are present.',
True, False);
ModelsPage.Add('Download the models now (recommended)');
ModelsPage.Values[0] := True;
end;
function WantModels: Boolean;
begin
Result := ModelsPage.Values[0];
end;
// The WebView2 runtime registers itself under EdgeUpdate with a non-empty
// version. Checked in three places because the runtime can be installed
// per-machine (both registry views on 64-bit) or per-user.
function WebView2Missing: Boolean;
const
CLIENT = '{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}';
var
pv: string;
begin
Result := True;
if RegQueryStringValue(HKLM, 'SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\' + CLIENT, 'pv', pv) and (pv <> '') then
Result := False
else if RegQueryStringValue(HKLM, 'SOFTWARE\Microsoft\EdgeUpdate\Clients\' + CLIENT, 'pv', pv) and (pv <> '') then
Result := False
else if RegQueryStringValue(HKCU, 'SOFTWARE\Microsoft\EdgeUpdate\Clients\' + CLIENT, 'pv', pv) and (pv <> '') then
Result := False;
end;