| |
|
|
| async function getJSON(url) { |
| const r = await fetch(url) |
| if (!r.ok) throw new Error(`${r.status} ${r.statusText}`) |
| return r.json() |
| } |
|
|
| async function postJSON(url, body) { |
| const r = await fetch(url, { |
| method: 'POST', |
| headers: { 'Content-Type': 'application/json' }, |
| body: JSON.stringify(body), |
| }) |
| if (!r.ok) throw new Error(`${r.status} ${r.statusText}`) |
| return r.json() |
| } |
|
|
| export const getRuntime = () => getJSON('/runtime') |
| export const getAnalytics = () => getJSON('/analytics') |
| export const getImage = (id) => getJSON(`/images/${id}`) |
| export const getViolation = (id) => getJSON(`/violations/${id}`) |
| export const getReviewQueue = () => getJSON('/review-queue') |
|
|
| export const uploadImage = async (file, cameraId) => { |
| const fd = new FormData() |
| fd.append('file', file) |
| const qs = cameraId ? `?camera_id=${encodeURIComponent(cameraId)}` : '' |
| const r = await fetch(`/images${qs}`, { method: 'POST', body: fd }) |
| if (!r.ok) throw new Error((await r.text()) || `${r.status}`) |
| return r.json() |
| } |
|
|
| export const listViolations = (params = {}) => { |
| const qs = new URLSearchParams() |
| for (const [k, v] of Object.entries(params)) if (v) qs.set(k, v) |
| return getJSON(`/violations?${qs.toString()}`) |
| } |
|
|
| export const reviewViolation = (id, decision, reviewer, note) => |
| postJSON(`/violations/${id}/review`, { decision, reviewer, note }) |
|
|
| |
| export const pollImage = async (id, onTick) => { |
| for (let i = 0; i < 90; i++) { |
| const d = await getImage(id) |
| onTick?.(d) |
| if (['completed', 'failed', 'undeterminable'].includes(d.status)) return d |
| await new Promise((r) => setTimeout(r, 1200)) |
| } |
| return getImage(id) |
| } |
|
|