Adds a 测试连接摄像头 button next to save; it builds the RTSP URL from the
current form fields and runs ffprobe (8s timeout) off the UI thread, then
shows a result popup (success WxH@fps, or a redacted failure). Exports
config.BuildRTSPURL and source.Probe/Redact for it. Cross-compiles for
Windows; config/source tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Comment out Gio's startup SetForegroundWindow/SetFocus in the vendored
os_windows.go (marked SILVER-POSE PATCH; reverts on re-vendor) so the
window no longer steals foreground on launch. Gio has no option for this.
- The fall confirm popup auto-closes 5s after opening (op.InvalidateCmd
schedules the redraw even with no live frames); '我已知晓' still closes early.
- Rename save buttons to 保存摄像头参数 / 保存常用检测参数. Cross-compiles for Windows.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a card() surface (white rounded panel, 1px #C8D4E3 stroke, 8px radius)
matching the light-Windows spec, and groups the monitor (video / status+
controls / gallery) and settings (camera / params / deps) into cards so the
gray-blue page shows through the gutters. Components were previously flat on
one background with no separation. Cross-compiles for Windows.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Settings tab is now an editable, scrollable form: camera connection
(host/port/channel/user/masked password/transport/timeout/low-latency) and
common detection params, each with a save button that writes the untracked
local config. cmd/silver-pose pre-fills from the local file, passes the
config path, and the controller reloads config on each Start so saved edits
apply next run. UI cross-compiles for Windows.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Config now accepts host/port/channel/username/password (untracked local
config only) or rtsp_url_env; net/url percent-encodes the userinfo so a
password with @/:/ builds a valid RTSP URL (fixes the manual %40 pain).
Adds WriteLocalCameraSource / WriteLocalEventTuning for the settings form.
Guards kept: still rejects a full url/rtsp_url; credentials stay out of the
config version; a test asserts the public example has no credentials.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Window opens at 80% of the primary display (Windows GetSystemMetrics).
- Gallery is now 2 columns x 3 rows and the right panel is narrower.
- Esc closes the full-image viewer (key focus + filter).
- Start/Stop grey out per running state (gtx.Disabled drops input); a hard
ReportIssue resets running so Start re-enables. Cross-compiles for Windows.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Right panel now shows connection+detection status on one line, small
start/stop buttons on one line, event text with the red-note inline, and a
3x3 reverse-chronological gallery of recent confirmed screenshots filling
the rest. Double-clicking a thumbnail opens a full-image overlay. Gallery
items are collected off the UI thread from confirmed updates (deduped by
event id) and each ImageOp is built once and cached. Cross-compiles for
Windows; no new deps.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Field ffmpeg reported 'Option rw_timeout not found' and exited, causing a
reconnect loop. rw_timeout is an avio/protocol option, not an RTSP demuxer
option; the RTSP socket timeout is build-specific (-stimeout / -timeout).
Omit it for portability — a dead TCP connection still ends decode and
triggers reconnect. Keeps transport and low-latency flags.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The stream worker discarded ffmpeg stderr, so reconnect loops were opaque.
Capture stderr and log it with the RTSP URL/credentials redacted, so the
real cause (auth, timeout, option, URL parse) is diagnosable without
leaking the source address.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
go mod vendor pins onnxruntime_go v1.12.1, Gio and the rest into v2/vendor
so go run/build work without hitting proxy.golang.org (blocked/slow in
China). Verified: CGO_ENABLED=1 go build -mod=vendor ./internal/spike and
GOOS=windows go build -mod=vendor ./internal/ui both pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
v1.31.0 requested ORT_API_VERSION 26 (onnxruntime 1.26); the field DLL is
Python 3.8's onnxruntime 1.19.2 (API 19), so GetApi(26) returned NULL and
init failed. v1.12.1 targets ORT API 19, matching the existing DLL with no
download. Verified: native cgo build of internal/spike compiles ort.go
against v1.12.1; Gio UI still cross-compiles for Windows.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The controller discarded the wrapped error and showed only a generic
message. Log the actual cause (e.g. onnxruntime version mismatch) to the
console so field startup failures are diagnosable.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rewrites internal/ui/window.go in Gio, keeping the Window interface
(NewWindow/Run/Present/PresentAlert/ReportIssue) and the pure-Go ViewModel.
Background updates mutate shared state under a lock and Invalidate; the Gio
loop renders the latest frame. Dual tabs, widget.Image for render's RGBA, a
self-drawn confirm dialog and a MessageBeep sound. Drops lxn/walk (and the
TTM_ADDTOOL/comctl class of problems). Verified via GOOS=windows CGO_ENABLED=0
build of the UI packages; full app build needs Windows+CGo for onnxruntime.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds cmd/gio-spike: a minimal Gio window (dual tabs, an *image.RGBA video
area, start/stop) that avoids the Walk TTM_ADDTOOL/comctl manifest problem
entirely. Verified via GOOS=windows CGO_ENABLED=0 go build (11MB single
exe). Windows visual smoke pending. Existing Walk ui-spike left untouched.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
annotate_frame draws Chinese labels (e.g. '确认摔倒 P-0001') using a CJK
font via Pillow when available (Windows uses Microsoft YaHei), and falls
back to the ASCII cv2 label when Pillow or a CJK font is missing. 86 tests
pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds _FrameGrabber which decodes in a background thread and keeps only the
newest frame; VideoSource drop_stale (STREAM only) returns the latest frame
so a slow consumer never builds a backlog. app enables it for streams.
REPLAY is unchanged. 82 tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds write_local_event_tuning and a sensitivity group (confirm window,
horizontal angle, require-rapid-drop, require-lower-body) that persists to
the untracked local config and applies next start. 79 tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
v1/report.py reads events.jsonl and lists each confirmed event with its
latency (flags the 1-3s target) and screenshot, or reports a clean pass
when empty. Supports T-204 latency records and false-alarm counting.
78 tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a mid-stream drop recovery test and a pipeline test proving a
disconnected frame yields no events and interrupts a pending suspect
(stream loss never alarms). Live preview and fall detection on the real
Hikvision stream were confirmed on Windows. 74 tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
cv2.putText only supports ASCII (Hershey fonts); the middle-dot in the
label rendered as garbage on saved screenshots. screenshot_label builds
an ASCII-only 'ID STATE' string for the annotation; the Qt live-view
label is unchanged. 72 tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds configurable event.require_rapid_drop (default off), require_lower_body
(default off) and horizontal_angle_threshold_degrees (default 45). With the
lenient defaults a sustained horizontal pose alone enters SUSPECT and confirms
after the confirm window, which is now the main false-positive guard; missing
knees/ankles no longer reject the pose. Thresholds flow into config_version.
End-to-end smoke confirms a lying pose; 70 tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PersonAnalysis now carries the policy Evidence; view_model builds a Qt-free
per-person diagnostic line (acc/horiz/ang/rapid/cand/state, or the reject
reason) and VideoView overlays it in a corner. Read-only, no decision change;
locates where a real fall stops. 67 tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Config gains source.transport (tcp/udp), timeout_seconds and low_latency;
build_ffmpeg_options assembles OPENCV_FFMPEG_CAPTURE_OPTIONS and app.py
sets it into the environment before opening the stream, so tuning lives
in config/settings instead of a launch script. Settings tab exposes a
dropdown/number/checkbox rather than the raw option string. 64 tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Settings tab gains a camera group (host/port/channel/user/masked password),
a background connection-test worker that probes one frame off the GUI
thread and shows it in a preview, and a save button that writes the
structured source to the untracked config.local.json. 60 tests pass;
Qt shell compiles and needs a Windows smoke.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Config accepts structured host/port/channel/username/password (or the
existing rtsp_url_env) and builds the RTSP URL with RFC 3986 percent-
encoded credentials, so passwords containing @/:/ no longer break parsing.
Credentials are excluded from config_version; a guard test keeps the
public example credential-free. probe_stream does a bounded connection
test. 59 tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
VideoSource STREAM connects to the real camera (1920x1080, monotonic
timestamps) and a bad address goes to retrying without alarm. Credentials
stay in the SILVER_POSE_RTSP_URL env var only; no address in the repo.
GUI preview and live pose overlay remain to be smoked on Windows.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A: PoseAdapter.set_confidence_threshold is applied on start, so the
settings model-confidence field actually affects inference.
B: config source.mode ('stream'|'replay') is explicit; app no longer
guesses the source type from the URL prefix.
C: FallStateMachine takes a session_id and from_config generates a
unique one per run, so event ids never collide across restarts
(no screenshot overwrite or duplicate JSONL identity in a day).
51 tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reconnect/state/idempotency logic is implemented and unit-tested; the
unmet acceptance is on-site Hikvision preview (T-203) and consented fall
and counter-example recordings with field safety (T-204, T-205). Not
marked DONE without real observable evidence.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
AlertDispatcher de-duplicates by event_id and fires each side effect once
per CONFIRMED: annotated screenshot, one JSONL line (config_version,
source_id, no rtsp/credentials), sound and popup via injectable sink.
44 tests pass; real-frame artifact smoke verified.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Qt-free view_model builds monitor view state and isolates the settings
draft from the running config snapshot; gui.py/app.py are a thin PyQt5
shell that only renders already-decided FrameAnalysis. 39 tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>