repzo 1.0.292 → 1.0.293
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.md +28 -0
- package/lib/index.d.ts +244 -2
- package/lib/index.js +541 -0
- package/lib/types/index.d.ts +4530 -1
- package/package.json +1 -1
- package/src/index.ts +1270 -0
- package/src/oas/activity-ai-object-detection-session-frame.yaml +600 -0
- package/src/oas/ai-object-detection-assigned-missions.yaml +283 -0
- package/src/oas/ai-object-detection-assignment-rule.yaml +357 -0
- package/src/oas/ai-object-detection-category.yaml +338 -0
- package/src/oas/ai-object-detection-dataset.yaml +342 -0
- package/src/oas/ai-object-detection-detection-settings.yaml +410 -0
- package/src/oas/ai-object-detection-inference.yaml +818 -0
- package/src/oas/ai-object-detection-label-group.yaml +265 -0
- package/src/oas/ai-object-detection-label-report.yaml +366 -0
- package/src/oas/ai-object-detection-label.yaml +395 -0
- package/src/oas/ai-object-detection-metric-result.yaml +734 -0
- package/src/oas/ai-object-detection-metric.yaml +559 -0
- package/src/oas/ai-object-detection-mission-results.yaml +370 -0
- package/src/oas/ai-object-detection-mission-set.yaml +250 -0
- package/src/oas/ai-object-detection-mission.yaml +349 -0
- package/src/oas/ai-object-detection-model-version-epoch.yaml +214 -0
- package/src/oas/ai-object-detection-model-version-train-agent.yaml +88 -0
- package/src/oas/ai-object-detection-model-version.yaml +567 -0
- package/src/oas/ai-object-detection-model.yaml +369 -0
- package/src/oas/ai-object-detection-segment.yaml +301 -0
- package/src/oas/ai-object-detection-session-analysis.yaml +1306 -0
- package/src/oas/ai-object-detection-session-election.yaml +193 -0
- package/src/oas/ai-object-detection-session-insight.yaml +418 -0
- package/src/oas/ai-object-detection-session.yaml +840 -0
- package/src/oas/ai-object-detection-settings.yaml +249 -0
- package/src/oas/ai-object-detection-task.yaml +1007 -0
- package/src/oas/object-detection-analytics-report.yaml +674 -0
- package/src/types/index.ts +5156 -1
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
openapi: 3.0.3
|
|
2
|
+
info:
|
|
3
|
+
title: Repzo API - AI Object Detection Session Election
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
description: |
|
|
6
|
+
Materializes an election-playground result as a NEW object-detection
|
|
7
|
+
session. The dashboard's election playground simulates stack-then-elect
|
|
8
|
+
frame election over a session captured in the AR app's election-debug mode
|
|
9
|
+
(every stacked frame uploaded); this endpoint saves the elected subset as
|
|
10
|
+
a real session so it can go through the normal analysis pipeline.
|
|
11
|
+
|
|
12
|
+
**What it does.** The source session document is cloned — `device`,
|
|
13
|
+
`capture_settings`, `coverage_m2`, `client` and `status` copied,
|
|
14
|
+
`session_id` suffixed `-E<n>` (n = 1 + prior elections of that source)
|
|
15
|
+
and `source_session` set for provenance. The elected tasks are first
|
|
16
|
+
SCREENED against the namespace detection-settings ERROR tier in capture
|
|
17
|
+
order (`sharpness`, `tracking`, `too_near`/`too_far`, `yaw_delta`/
|
|
18
|
+
`pitch_delta`/`roll_delta` vs the previous kept frame); excluded frames
|
|
19
|
+
stay on the source session (they keep counting toward coverage) and are
|
|
20
|
+
listed under `election_excluded`. The surviving tasks are duplicated onto
|
|
21
|
+
the new session referencing the SAME media blobs (no image/depth copies)
|
|
22
|
+
with annotation state reset, so inference re-runs from scratch.
|
|
23
|
+
|
|
24
|
+
**Session gates & verdict.** `rejection_reasons` collects the session
|
|
25
|
+
gates that fired — `coverage_below_target` (device `coverage_m2` below the
|
|
26
|
+
configured target), `jump_detected` (adjacent kept frames farther apart
|
|
27
|
+
than a frame footprint, unless `allow_jump`), `too_many_elected` (kept
|
|
28
|
+
frames exceed coverage / avg footprint × allowance). `session_score` is
|
|
29
|
+
the average frame quality over ALL frames of the source session (0..1)
|
|
30
|
+
and `session_verdict` is `rejected` when any gate fired, else banded from
|
|
31
|
+
the score (`excellent` / `good` / `acceptable`). A `rejected` verdict
|
|
32
|
+
also suppresses the category auto-analysis on upload-complete.
|
|
33
|
+
|
|
34
|
+
**Who calls it & lifecycle.** Admin / API-key callers from the dashboard.
|
|
35
|
+
Create-only — `find`/`get`/`update`/`patch`/`remove` return 405. The new
|
|
36
|
+
row lives in the regular `ai-object-detection-session` collection
|
|
37
|
+
(namespace-scoped via the caller's token; `company_namespace` is
|
|
38
|
+
server-injected) and is read/managed through that service.
|
|
39
|
+
servers:
|
|
40
|
+
- url: https://sv.api.repzo.me
|
|
41
|
+
security:
|
|
42
|
+
- ApiKeyAuth: []
|
|
43
|
+
- JwtAuth: []
|
|
44
|
+
paths:
|
|
45
|
+
/ai-object-detection-session-election:
|
|
46
|
+
post:
|
|
47
|
+
summary: Save an elected frame subset as a new session
|
|
48
|
+
description: >-
|
|
49
|
+
Clones the source session and the chosen tasks (after error-tier
|
|
50
|
+
screening) into a new session with the same media references and a
|
|
51
|
+
fresh annotation state. Returns the new session document.
|
|
52
|
+
operationId: createAiObjectDetectionSessionElection
|
|
53
|
+
requestBody:
|
|
54
|
+
required: true
|
|
55
|
+
content:
|
|
56
|
+
application/json:
|
|
57
|
+
schema:
|
|
58
|
+
$ref: "#/components/schemas/ElectionRequest"
|
|
59
|
+
responses:
|
|
60
|
+
"201":
|
|
61
|
+
description: The newly created session document (a regular `ai-object-detection-session` row).
|
|
62
|
+
content:
|
|
63
|
+
application/json:
|
|
64
|
+
schema:
|
|
65
|
+
$ref: "#/components/schemas/ElectedSession"
|
|
66
|
+
"400":
|
|
67
|
+
description: >-
|
|
68
|
+
Missing `session`, empty `task_ids`, more than 500 task ids, task
|
|
69
|
+
ids that do not belong to the source session, or every elected
|
|
70
|
+
frame fails the error-tier limits (nothing to materialize).
|
|
71
|
+
"404":
|
|
72
|
+
description: Source session not found in the caller's namespace.
|
|
73
|
+
components:
|
|
74
|
+
securitySchemes:
|
|
75
|
+
ApiKeyAuth:
|
|
76
|
+
type: apiKey
|
|
77
|
+
in: header
|
|
78
|
+
name: api-key
|
|
79
|
+
description: |
|
|
80
|
+
Server-issued API key. Also accepted via the `x-api-key` header or the
|
|
81
|
+
`?apiKey=` query parameter as fallbacks.
|
|
82
|
+
JwtAuth:
|
|
83
|
+
type: apiKey
|
|
84
|
+
in: header
|
|
85
|
+
name: Authorization
|
|
86
|
+
description: |
|
|
87
|
+
Raw JWT in the `Authorization` header — **no `Bearer ` prefix**.
|
|
88
|
+
Obtained from `POST /authenticate` (admin / rep / client login).
|
|
89
|
+
schemas:
|
|
90
|
+
ElectionRequest:
|
|
91
|
+
type: object
|
|
92
|
+
required: [session, task_ids]
|
|
93
|
+
properties:
|
|
94
|
+
session:
|
|
95
|
+
type: string
|
|
96
|
+
description: Source `ai-object-detection-session` `_id`.
|
|
97
|
+
task_ids:
|
|
98
|
+
type: array
|
|
99
|
+
minItems: 1
|
|
100
|
+
maxItems: 500
|
|
101
|
+
items: { type: string }
|
|
102
|
+
description: >-
|
|
103
|
+
Elected task `_id`s — must all belong to the source session.
|
|
104
|
+
config_snapshot:
|
|
105
|
+
type: object
|
|
106
|
+
additionalProperties: true
|
|
107
|
+
description: >-
|
|
108
|
+
Optional playground formula parameters used for this election.
|
|
109
|
+
Accepted for provenance only — not persisted on the session.
|
|
110
|
+
company_namespace:
|
|
111
|
+
type: array
|
|
112
|
+
items: { type: string }
|
|
113
|
+
description: Optional tenant namespace override for SDK callers.
|
|
114
|
+
UserRef:
|
|
115
|
+
type: object
|
|
116
|
+
description: Compact actor reference (rep or admin).
|
|
117
|
+
properties:
|
|
118
|
+
_id: { type: string }
|
|
119
|
+
type: { type: string, enum: [admin, rep] }
|
|
120
|
+
name: { type: string }
|
|
121
|
+
rep: { type: string }
|
|
122
|
+
admin: { type: string }
|
|
123
|
+
ElectedSession:
|
|
124
|
+
type: object
|
|
125
|
+
description: >-
|
|
126
|
+
The materialized session — a regular `ai-object-detection-session`
|
|
127
|
+
document (see that service's `SessionSchema` for every field); the
|
|
128
|
+
election-specific fields are always present here.
|
|
129
|
+
properties:
|
|
130
|
+
_id: { type: string }
|
|
131
|
+
session_id:
|
|
132
|
+
type: string
|
|
133
|
+
description: "Source id with an election suffix, e.g. `AB12CD34-E1`."
|
|
134
|
+
source_session:
|
|
135
|
+
type: string
|
|
136
|
+
description: The source session `_id` (provenance).
|
|
137
|
+
status:
|
|
138
|
+
type: string
|
|
139
|
+
enum:
|
|
140
|
+
[open, uploaded, infer_in_progress, inferred, rearbitrating, failed]
|
|
141
|
+
description: Copied from the source session.
|
|
142
|
+
device: { type: object, additionalProperties: true }
|
|
143
|
+
capture_settings: { type: object, additionalProperties: true }
|
|
144
|
+
coverage_m2:
|
|
145
|
+
type: number
|
|
146
|
+
description: Copied from the source (total coverage INCLUDES the excluded frames).
|
|
147
|
+
client: { type: string }
|
|
148
|
+
session_score:
|
|
149
|
+
type: number
|
|
150
|
+
description: Average frame quality over ALL frames of the source session, 0..1.
|
|
151
|
+
session_verdict:
|
|
152
|
+
type: string
|
|
153
|
+
enum: [excellent, good, acceptable, rejected]
|
|
154
|
+
rejection_reasons:
|
|
155
|
+
type: array
|
|
156
|
+
items:
|
|
157
|
+
type: string
|
|
158
|
+
enum: [coverage_below_target, jump_detected, too_many_elected]
|
|
159
|
+
election_excluded:
|
|
160
|
+
type: array
|
|
161
|
+
description: Error-tier frames excluded from the clone.
|
|
162
|
+
items:
|
|
163
|
+
type: object
|
|
164
|
+
properties:
|
|
165
|
+
task: { type: string }
|
|
166
|
+
violations:
|
|
167
|
+
type: array
|
|
168
|
+
items:
|
|
169
|
+
type: string
|
|
170
|
+
enum:
|
|
171
|
+
[
|
|
172
|
+
sharpness,
|
|
173
|
+
tracking,
|
|
174
|
+
too_near,
|
|
175
|
+
too_far,
|
|
176
|
+
yaw_delta,
|
|
177
|
+
pitch_delta,
|
|
178
|
+
roll_delta,
|
|
179
|
+
]
|
|
180
|
+
frames_total: { type: number }
|
|
181
|
+
frames_accepted: { type: number }
|
|
182
|
+
tasks_count: { type: number }
|
|
183
|
+
detections_count: { type: number }
|
|
184
|
+
objects_count: { type: number }
|
|
185
|
+
creator:
|
|
186
|
+
$ref: "#/components/schemas/UserRef"
|
|
187
|
+
disabled: { type: boolean }
|
|
188
|
+
company_namespace:
|
|
189
|
+
type: array
|
|
190
|
+
items: { type: string }
|
|
191
|
+
description: Tenant key. Server-injected — never accept from clients.
|
|
192
|
+
createdAt: { type: string, format: date-time }
|
|
193
|
+
updatedAt: { type: string, format: date-time }
|
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
openapi: 3.0.3
|
|
2
|
+
info:
|
|
3
|
+
title: Repzo API - AI Object Detection Session Insight
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
description: |
|
|
6
|
+
**Session insight** — retail shelf intelligence computed ON READ from a
|
|
7
|
+
shelf-scan session's latest successful analysis (or an explicit analysis
|
|
8
|
+
id). Nothing is persisted or cached: edits to the analysis, the labels or
|
|
9
|
+
their product links reflect on the next request.
|
|
10
|
+
|
|
11
|
+
**What it derives.** Facings are the FRONT-ROW shelved objects of the
|
|
12
|
+
analysis's stored board-first shelf composition (composed on the fly for
|
|
13
|
+
legacy analyses that predate it), laid out along the scene's shelf axis û.
|
|
14
|
+
From them:
|
|
15
|
+
- `shelves[]` — facing counts, Σ linear cm, occupied span, utilization.
|
|
16
|
+
- `share_of_shelf` — rollup rows per vocabulary kind: `by_label` always;
|
|
17
|
+
`by_label_group` / `by_brand` / `by_category` / `by_subcategory` /
|
|
18
|
+
`by_product` appear only when the scene's labels LINK to entities of
|
|
19
|
+
that kind (links live on `ai-object-detection-label`).
|
|
20
|
+
- `blocking` — "merchandised together?": maximal same-shelf runs of a
|
|
21
|
+
group's facings, merged vertically across adjacent shelves when their
|
|
22
|
+
u-intervals overlap; interrupting labels are ranked.
|
|
23
|
+
- `objects` (`include_objects=true`) — planogram-style facing dump per
|
|
24
|
+
shelf, positions re-based to each shelf's left edge (cm).
|
|
25
|
+
- `adjacency` (`include_adjacency=true`) — who stands next to whom.
|
|
26
|
+
|
|
27
|
+
**Questions (POST).** Up to 20 free-text or structured questions answered
|
|
28
|
+
in order. Intent = share_of_shelf / blocking / adjacency; the target
|
|
29
|
+
resolves by id → exact name → substring → fuzzy tokens against the
|
|
30
|
+
scene's vocabulary; unresolved answers carry `reason` + `suggestions`.
|
|
31
|
+
Each answer includes a human-readable `narrative`.
|
|
32
|
+
|
|
33
|
+
**Config.** `default_facing_width_m` substitutes facings with no measured
|
|
34
|
+
size; `block_min_overlap_m` / `block_overlap_frac` tune the vertical
|
|
35
|
+
block merge. (`min_shelf_gap_m` / `shelf_gap_height_factor` are echoed
|
|
36
|
+
for contract compatibility — shelf levels now come from the analysis's
|
|
37
|
+
stored composition, tuned via the analysis `shelf_*` settings.)
|
|
38
|
+
|
|
39
|
+
Positions are metres (AR world frame); product sizes centimetres.
|
|
40
|
+
Namespace-scoped via the caller's token; read-only (PUT/PATCH/DELETE are
|
|
41
|
+
rejected). Admins read any session; a REP token reads only insights of
|
|
42
|
+
sessions THAT REP scanned (the mobile Retail Insights screen's read).
|
|
43
|
+
servers:
|
|
44
|
+
- url: https://sv.api.repzo.me
|
|
45
|
+
security:
|
|
46
|
+
- ApiKeyAuth: []
|
|
47
|
+
- JwtAuth: []
|
|
48
|
+
paths:
|
|
49
|
+
/ai-object-detection-session-insight:
|
|
50
|
+
get:
|
|
51
|
+
summary: Compute the insight for a session / analysis
|
|
52
|
+
operationId: findAiObjectDetectionSessionInsight
|
|
53
|
+
parameters:
|
|
54
|
+
- in: query
|
|
55
|
+
name: session
|
|
56
|
+
description: "Session `_id` — reads its LATEST successful analysis. One of `session` / `analysis` is required."
|
|
57
|
+
schema: { type: string }
|
|
58
|
+
- in: query
|
|
59
|
+
name: analysis
|
|
60
|
+
description: "Explicit analysis `_id` (must have `status: success`)."
|
|
61
|
+
schema: { type: string }
|
|
62
|
+
- in: query
|
|
63
|
+
name: include_objects
|
|
64
|
+
description: "Add the planogram-style facing dump per shelf (only the literal `true` is honoured)."
|
|
65
|
+
schema: { type: boolean }
|
|
66
|
+
- in: query
|
|
67
|
+
name: include_adjacency
|
|
68
|
+
description: "Add label-level neighbour counts (only the literal `true` is honoured)."
|
|
69
|
+
schema: { type: boolean }
|
|
70
|
+
responses:
|
|
71
|
+
"200":
|
|
72
|
+
description: The freshly computed insight payload (a single object — not paginated).
|
|
73
|
+
content:
|
|
74
|
+
application/json:
|
|
75
|
+
schema:
|
|
76
|
+
$ref: "#/components/schemas/SessionInsight"
|
|
77
|
+
"400":
|
|
78
|
+
description: Neither session nor analysis given, or the analysis is not successful.
|
|
79
|
+
"403":
|
|
80
|
+
description: A REP token asked for a session that rep did not scan.
|
|
81
|
+
"404":
|
|
82
|
+
description: No matching analysis (or the session has no successful analysis yet).
|
|
83
|
+
post:
|
|
84
|
+
summary: Compute the insight and answer questions
|
|
85
|
+
operationId: createAiObjectDetectionSessionInsight
|
|
86
|
+
requestBody:
|
|
87
|
+
required: true
|
|
88
|
+
content:
|
|
89
|
+
application/json:
|
|
90
|
+
schema:
|
|
91
|
+
type: object
|
|
92
|
+
properties:
|
|
93
|
+
session:
|
|
94
|
+
type: string
|
|
95
|
+
description: "Session `_id` — one of `session` / `analysis` is required."
|
|
96
|
+
analysis: { type: string }
|
|
97
|
+
questions:
|
|
98
|
+
type: array
|
|
99
|
+
maxItems: 20
|
|
100
|
+
description: Free-text strings and/or structured questions, answered in order.
|
|
101
|
+
items:
|
|
102
|
+
oneOf:
|
|
103
|
+
- type: string
|
|
104
|
+
- $ref: "#/components/schemas/InsightQuestion"
|
|
105
|
+
config:
|
|
106
|
+
$ref: "#/components/schemas/InsightConfig"
|
|
107
|
+
include_objects: { type: boolean }
|
|
108
|
+
include_adjacency: { type: boolean }
|
|
109
|
+
responses:
|
|
110
|
+
"201":
|
|
111
|
+
description: "The insight payload plus `answers[]` (one per question, in order)."
|
|
112
|
+
content:
|
|
113
|
+
application/json:
|
|
114
|
+
schema:
|
|
115
|
+
$ref: "#/components/schemas/SessionInsight"
|
|
116
|
+
"400":
|
|
117
|
+
description: "Neither session nor analysis given, more than 20 questions, or the analysis is not successful."
|
|
118
|
+
"403":
|
|
119
|
+
description: A REP token asked for a session that rep did not scan.
|
|
120
|
+
"404":
|
|
121
|
+
description: No matching analysis (or the session has no successful analysis yet).
|
|
122
|
+
/ai-object-detection-session-insight/{id}:
|
|
123
|
+
get:
|
|
124
|
+
summary: Compute the insight for a session (deep link)
|
|
125
|
+
description: The path id is read as a SESSION id.
|
|
126
|
+
operationId: getAiObjectDetectionSessionInsight
|
|
127
|
+
parameters:
|
|
128
|
+
- in: path
|
|
129
|
+
name: id
|
|
130
|
+
required: true
|
|
131
|
+
schema: { type: string }
|
|
132
|
+
responses:
|
|
133
|
+
"200":
|
|
134
|
+
description: The freshly computed insight payload.
|
|
135
|
+
content:
|
|
136
|
+
application/json:
|
|
137
|
+
schema:
|
|
138
|
+
$ref: "#/components/schemas/SessionInsight"
|
|
139
|
+
"403":
|
|
140
|
+
description: A REP token asked for a session that rep did not scan.
|
|
141
|
+
"404":
|
|
142
|
+
description: The session has no successful analysis yet.
|
|
143
|
+
components:
|
|
144
|
+
securitySchemes:
|
|
145
|
+
ApiKeyAuth:
|
|
146
|
+
type: apiKey
|
|
147
|
+
in: header
|
|
148
|
+
name: api-key
|
|
149
|
+
description: |
|
|
150
|
+
Server-issued API key. Also accepted via the `x-api-key` header or the
|
|
151
|
+
`?apiKey=` query parameter as fallbacks.
|
|
152
|
+
JwtAuth:
|
|
153
|
+
type: apiKey
|
|
154
|
+
in: header
|
|
155
|
+
name: Authorization
|
|
156
|
+
description: |
|
|
157
|
+
Raw JWT in the `Authorization` header — **no `Bearer ` prefix**.
|
|
158
|
+
Obtained from `POST /authenticate` (admin / rep / client login).
|
|
159
|
+
schemas:
|
|
160
|
+
InsightConfig:
|
|
161
|
+
type: object
|
|
162
|
+
description: All optional — invalid values fall back to the defaults.
|
|
163
|
+
properties:
|
|
164
|
+
min_shelf_gap_m:
|
|
165
|
+
type: number
|
|
166
|
+
default: 0.06
|
|
167
|
+
description: Echoed for compatibility — shelf levels come from the stored composition.
|
|
168
|
+
shelf_gap_height_factor:
|
|
169
|
+
type: number
|
|
170
|
+
default: 0.35
|
|
171
|
+
description: Echoed for compatibility.
|
|
172
|
+
default_facing_width_m:
|
|
173
|
+
type: number
|
|
174
|
+
default: 0.08
|
|
175
|
+
description: Fallback facing width (m) when a facing has no measured size.
|
|
176
|
+
block_min_overlap_m:
|
|
177
|
+
type: number
|
|
178
|
+
default: 0.03
|
|
179
|
+
description: Vertical block merge — required axis overlap (m) between adjacent-shelf runs…
|
|
180
|
+
block_overlap_frac:
|
|
181
|
+
type: number
|
|
182
|
+
default: 0.5
|
|
183
|
+
description: "…or this fraction of the narrower run's width, whichever is smaller."
|
|
184
|
+
InsightQuestion:
|
|
185
|
+
type: object
|
|
186
|
+
required: [type, target]
|
|
187
|
+
properties:
|
|
188
|
+
type:
|
|
189
|
+
type: string
|
|
190
|
+
enum: [share_of_shelf, blocking, adjacency]
|
|
191
|
+
target:
|
|
192
|
+
type: object
|
|
193
|
+
description: Resolved by `id` first, then exact name, then fuzzy match.
|
|
194
|
+
properties:
|
|
195
|
+
kind:
|
|
196
|
+
type: string
|
|
197
|
+
enum: [label, label_group, brand, category, subcategory, product]
|
|
198
|
+
id: { type: string }
|
|
199
|
+
name: { type: string }
|
|
200
|
+
InsightShareRow:
|
|
201
|
+
type: object
|
|
202
|
+
properties:
|
|
203
|
+
key: { type: string }
|
|
204
|
+
kind:
|
|
205
|
+
type: string
|
|
206
|
+
enum: [label, label_group, brand, category, subcategory, product]
|
|
207
|
+
name: { type: string }
|
|
208
|
+
facings: { type: number }
|
|
209
|
+
linear_cm: { type: number }
|
|
210
|
+
area_cm2: { type: number }
|
|
211
|
+
facing_share:
|
|
212
|
+
{ type: number, description: 0..1 of all detected facings. }
|
|
213
|
+
linear_share: { type: number }
|
|
214
|
+
area_share: { type: number }
|
|
215
|
+
shelves:
|
|
216
|
+
type: array
|
|
217
|
+
items:
|
|
218
|
+
type: object
|
|
219
|
+
properties:
|
|
220
|
+
shelf_index: { type: number }
|
|
221
|
+
facings: { type: number }
|
|
222
|
+
linear_cm: { type: number }
|
|
223
|
+
linear_share_of_shelf: { type: number }
|
|
224
|
+
labels:
|
|
225
|
+
type: array
|
|
226
|
+
items:
|
|
227
|
+
type: object
|
|
228
|
+
properties:
|
|
229
|
+
label_id: { type: string }
|
|
230
|
+
label_name: { type: string }
|
|
231
|
+
facings: { type: number }
|
|
232
|
+
InsightBlocking:
|
|
233
|
+
type: object
|
|
234
|
+
properties:
|
|
235
|
+
key: { type: string }
|
|
236
|
+
name: { type: string }
|
|
237
|
+
narrative: { type: string }
|
|
238
|
+
present: { type: boolean }
|
|
239
|
+
facings: { type: number }
|
|
240
|
+
labels_present:
|
|
241
|
+
type: array
|
|
242
|
+
items:
|
|
243
|
+
type: object
|
|
244
|
+
properties:
|
|
245
|
+
label_id: { type: string }
|
|
246
|
+
label_name: { type: string }
|
|
247
|
+
facings: { type: number }
|
|
248
|
+
blocks_count: { type: number }
|
|
249
|
+
is_single_block:
|
|
250
|
+
type: boolean
|
|
251
|
+
description: True when every facing of the group sits in ONE contiguous block.
|
|
252
|
+
largest_block_facings: { type: number }
|
|
253
|
+
largest_block_share: { type: number }
|
|
254
|
+
blocks:
|
|
255
|
+
type: array
|
|
256
|
+
items:
|
|
257
|
+
type: object
|
|
258
|
+
properties:
|
|
259
|
+
shelves:
|
|
260
|
+
type: array
|
|
261
|
+
items: { type: number }
|
|
262
|
+
facings: { type: number }
|
|
263
|
+
runs:
|
|
264
|
+
type: array
|
|
265
|
+
items:
|
|
266
|
+
type: object
|
|
267
|
+
properties:
|
|
268
|
+
shelf_index: { type: number }
|
|
269
|
+
t0: { type: number, description: Left edge along û (m). }
|
|
270
|
+
t1: { type: number }
|
|
271
|
+
facings: { type: number }
|
|
272
|
+
facing_ids:
|
|
273
|
+
type: array
|
|
274
|
+
items: { type: string }
|
|
275
|
+
interrupters:
|
|
276
|
+
type: array
|
|
277
|
+
description: Foreign labels breaking the block, ranked by interrupting facings.
|
|
278
|
+
items:
|
|
279
|
+
type: object
|
|
280
|
+
properties:
|
|
281
|
+
label_id: { type: string }
|
|
282
|
+
label_name: { type: string }
|
|
283
|
+
facings: { type: number }
|
|
284
|
+
shelves_spanned:
|
|
285
|
+
type: array
|
|
286
|
+
items: { type: number }
|
|
287
|
+
SessionInsight:
|
|
288
|
+
type: object
|
|
289
|
+
properties:
|
|
290
|
+
session: { type: string }
|
|
291
|
+
analysis: { type: string }
|
|
292
|
+
model_version: { type: string }
|
|
293
|
+
analysis_finished_at: { type: number }
|
|
294
|
+
computed_at:
|
|
295
|
+
type: number
|
|
296
|
+
description: Unix ms — always freshly computed, never cached.
|
|
297
|
+
config_used:
|
|
298
|
+
$ref: "#/components/schemas/InsightConfig"
|
|
299
|
+
scene:
|
|
300
|
+
type: object
|
|
301
|
+
properties:
|
|
302
|
+
facings_placed: { type: number }
|
|
303
|
+
objects_skipped:
|
|
304
|
+
type: number
|
|
305
|
+
description: Analysis objects not counted as facings (back rows / unshelved).
|
|
306
|
+
shelf_count: { type: number }
|
|
307
|
+
axis:
|
|
308
|
+
type: object
|
|
309
|
+
description: Unit shelf-axis direction û in the horizontal plane.
|
|
310
|
+
properties:
|
|
311
|
+
dir_x: { type: number }
|
|
312
|
+
dir_z: { type: number }
|
|
313
|
+
totals:
|
|
314
|
+
type: object
|
|
315
|
+
properties:
|
|
316
|
+
facings: { type: number }
|
|
317
|
+
linear_cm: { type: number }
|
|
318
|
+
area_cm2: { type: number }
|
|
319
|
+
shelves:
|
|
320
|
+
type: array
|
|
321
|
+
items:
|
|
322
|
+
type: object
|
|
323
|
+
properties:
|
|
324
|
+
index: { type: number, description: 0 = bottom shelf. }
|
|
325
|
+
y_base_m:
|
|
326
|
+
{ type: number, description: Board level (m, AR world frame). }
|
|
327
|
+
facings: { type: number }
|
|
328
|
+
linear_cm: { type: number }
|
|
329
|
+
span_cm: { type: number }
|
|
330
|
+
utilization:
|
|
331
|
+
type: number
|
|
332
|
+
description: linear_cm / span_cm — how much of the used span is product.
|
|
333
|
+
share_of_shelf:
|
|
334
|
+
type: object
|
|
335
|
+
description: "Keys: `by_label` always; `by_label_group` / `by_brand` / `by_category` / `by_subcategory` / `by_product` only when links exist."
|
|
336
|
+
additionalProperties:
|
|
337
|
+
type: array
|
|
338
|
+
items:
|
|
339
|
+
$ref: "#/components/schemas/InsightShareRow"
|
|
340
|
+
blocking:
|
|
341
|
+
type: object
|
|
342
|
+
description: Same keys as share_of_shelf; rows only for present groups.
|
|
343
|
+
additionalProperties:
|
|
344
|
+
type: array
|
|
345
|
+
items:
|
|
346
|
+
$ref: "#/components/schemas/InsightBlocking"
|
|
347
|
+
objects:
|
|
348
|
+
type: array
|
|
349
|
+
description: "Only with `include_objects=true` — facings left→right per shelf."
|
|
350
|
+
items:
|
|
351
|
+
type: object
|
|
352
|
+
properties:
|
|
353
|
+
shelf_index: { type: number }
|
|
354
|
+
facings:
|
|
355
|
+
type: array
|
|
356
|
+
items:
|
|
357
|
+
type: object
|
|
358
|
+
properties:
|
|
359
|
+
id: { type: string }
|
|
360
|
+
label_id: { type: string }
|
|
361
|
+
label_name: { type: string }
|
|
362
|
+
position: { type: number }
|
|
363
|
+
from_cm:
|
|
364
|
+
type: number
|
|
365
|
+
description: Re-based to the shelf's left-most facing.
|
|
366
|
+
to_cm: { type: number }
|
|
367
|
+
w_cm: { type: number }
|
|
368
|
+
h_cm: { type: number }
|
|
369
|
+
confidence: { type: number }
|
|
370
|
+
adjacency:
|
|
371
|
+
type: array
|
|
372
|
+
description: "Only with `include_adjacency=true`."
|
|
373
|
+
items:
|
|
374
|
+
type: object
|
|
375
|
+
properties:
|
|
376
|
+
label_id: { type: string }
|
|
377
|
+
label_name: { type: string }
|
|
378
|
+
neighbors:
|
|
379
|
+
type: array
|
|
380
|
+
items:
|
|
381
|
+
type: object
|
|
382
|
+
properties:
|
|
383
|
+
label_id: { type: string }
|
|
384
|
+
label_name: { type: string }
|
|
385
|
+
count: { type: number }
|
|
386
|
+
answers:
|
|
387
|
+
type: array
|
|
388
|
+
description: Present on POST responses only — one per question, in order.
|
|
389
|
+
items:
|
|
390
|
+
type: object
|
|
391
|
+
properties:
|
|
392
|
+
question:
|
|
393
|
+
oneOf:
|
|
394
|
+
- type: string
|
|
395
|
+
- $ref: "#/components/schemas/InsightQuestion"
|
|
396
|
+
type:
|
|
397
|
+
type: string
|
|
398
|
+
enum: [share_of_shelf, blocking, adjacency]
|
|
399
|
+
resolved: { type: boolean }
|
|
400
|
+
reason: { type: string }
|
|
401
|
+
suggestions:
|
|
402
|
+
type: array
|
|
403
|
+
items: { type: string }
|
|
404
|
+
target:
|
|
405
|
+
type: object
|
|
406
|
+
properties:
|
|
407
|
+
kind: { type: string }
|
|
408
|
+
name: { type: string }
|
|
409
|
+
label_ids:
|
|
410
|
+
type: array
|
|
411
|
+
items: { type: string }
|
|
412
|
+
result:
|
|
413
|
+
description: Share row, blocking result, or neighbour list per the question type.
|
|
414
|
+
oneOf:
|
|
415
|
+
- $ref: "#/components/schemas/InsightShareRow"
|
|
416
|
+
- $ref: "#/components/schemas/InsightBlocking"
|
|
417
|
+
- type: object
|
|
418
|
+
narrative: { type: string }
|