adjust api for newest karung admin
This commit is contained in:
1 parent
5b4d9d56d4
commit
d7d268ad48
4 files changed
+38
-19
No files matched your search
@@ -3,6 +3,9 @@ __pycache__/
|
|||||||
*.py[codz]
|
*.py[codz]
|
||||||
*$py.class
|
*$py.class
|
||||||
|
|
||||||
|
#superpower
|
||||||
|
docs
|
||||||
|
|
||||||
# C extensions
|
# C extensions
|
||||||
*.so
|
*.so
|
||||||
|
|
||||||
|
|||||||
+10
-2
@@ -183,6 +183,7 @@ def api_snapshot_image(category, filename):
|
|||||||
|
|
||||||
|
|
||||||
def _ensure_db():
|
def _ensure_db():
|
||||||
|
Path(DB_PATH).parent.mkdir(parents=True, exist_ok=True)
|
||||||
conn = sqlite3.connect(DB_PATH)
|
conn = sqlite3.connect(DB_PATH)
|
||||||
cur = conn.cursor()
|
cur = conn.cursor()
|
||||||
cur.execute(
|
cur.execute(
|
||||||
@@ -362,7 +363,7 @@ def _empty_counts():
|
|||||||
def _empty_current():
|
def _empty_current():
|
||||||
return {
|
return {
|
||||||
"counting_date": get_counting_date(),
|
"counting_date": get_counting_date(),
|
||||||
"count": 0,
|
"total_count": 0,
|
||||||
"counts": _empty_counts(),
|
"counts": _empty_counts(),
|
||||||
"zones": ZONES_META,
|
"zones": ZONES_META,
|
||||||
"start_time": None,
|
"start_time": None,
|
||||||
@@ -390,9 +391,16 @@ def _load_current_state():
|
|||||||
"zone_2": int(data.get("count_right", 0) or 0),
|
"zone_2": int(data.get("count_right", 0) or 0),
|
||||||
}
|
}
|
||||||
counts = _normalize_counts(counts)
|
counts = _normalize_counts(counts)
|
||||||
|
# Prefer total_count; fall back to legacy "count" then sum of zones.
|
||||||
|
if data.get("total_count") is not None:
|
||||||
|
total = int(data.get("total_count") or 0)
|
||||||
|
elif data.get("count") is not None:
|
||||||
|
total = int(data.get("count") or 0)
|
||||||
|
else:
|
||||||
|
total = sum(counts.values())
|
||||||
return {
|
return {
|
||||||
"counting_date": data.get("counting_date") or get_counting_date(),
|
"counting_date": data.get("counting_date") or get_counting_date(),
|
||||||
"count": int(data.get("count", sum(counts.values())) or 0),
|
"total_count": total,
|
||||||
"counts": counts,
|
"counts": counts,
|
||||||
"zones": ZONES_META,
|
"zones": ZONES_META,
|
||||||
"start_time": data.get("start_time"),
|
"start_time": data.get("start_time"),
|
||||||
|
|||||||
+9
-8
@@ -177,7 +177,8 @@ class CounterStore:
|
|||||||
# Preserve migrated zone_2 even if current config is 1 zone? Spec says
|
# Preserve migrated zone_2 even if current config is 1 zone? Spec says
|
||||||
# configured ids only — drop unknown keys from active counts.
|
# configured ids only — drop unknown keys from active counts.
|
||||||
state['counts'] = normalized
|
state['counts'] = normalized
|
||||||
state['count'] = sum(normalized.values())
|
state['total_count'] = sum(normalized.values())
|
||||||
|
state.pop('count', None)
|
||||||
state.pop('count_left', None)
|
state.pop('count_left', None)
|
||||||
state.pop('count_right', None)
|
state.pop('count_right', None)
|
||||||
state.setdefault('counted_event_ids', [])
|
state.setdefault('counted_event_ids', [])
|
||||||
@@ -208,7 +209,7 @@ class CounterStore:
|
|||||||
)
|
)
|
||||||
state['counted_event_ids'] = []
|
state['counted_event_ids'] = []
|
||||||
self.log(
|
self.log(
|
||||||
f"Resumed {current_date} with total={state['count']} "
|
f"Resumed {current_date} with total={state['total_count']} "
|
||||||
f"counts={state['counts']}"
|
f"counts={state['counts']}"
|
||||||
)
|
)
|
||||||
with open(self.state_file, 'w', encoding='utf-8') as f:
|
with open(self.state_file, 'w', encoding='utf-8') as f:
|
||||||
@@ -236,7 +237,7 @@ class CounterStore:
|
|||||||
counts = self._empty_counts()
|
counts = self._empty_counts()
|
||||||
self.current_state = {
|
self.current_state = {
|
||||||
'counting_date': counting_date,
|
'counting_date': counting_date,
|
||||||
'count': 0,
|
'total_count': 0,
|
||||||
'counts': counts,
|
'counts': counts,
|
||||||
'start_time': now,
|
'start_time': now,
|
||||||
'last_detection_time': now,
|
'last_detection_time': now,
|
||||||
@@ -264,7 +265,7 @@ class CounterStore:
|
|||||||
counted = False
|
counted = False
|
||||||
event_key = f"{track_id}_{zone_id}"
|
event_key = f"{track_id}_{zone_id}"
|
||||||
if event_key not in self.current_state['counted_event_ids']:
|
if event_key not in self.current_state['counted_event_ids']:
|
||||||
self.current_state['count'] += 1
|
self.current_state['total_count'] += 1
|
||||||
self.current_state['counts'][zone_id] = (
|
self.current_state['counts'][zone_id] = (
|
||||||
int(self.current_state['counts'].get(zone_id, 0)) + 1
|
int(self.current_state['counts'].get(zone_id, 0)) + 1
|
||||||
)
|
)
|
||||||
@@ -272,14 +273,14 @@ class CounterStore:
|
|||||||
counted = True
|
counted = True
|
||||||
self.log(
|
self.log(
|
||||||
f'Counted {zone_id} (track {track_id}) | {counting_date} '
|
f'Counted {zone_id} (track {track_id}) | {counting_date} '
|
||||||
f'total: {self.current_state["count"]} '
|
f'total: {self.current_state["total_count"]} '
|
||||||
f'counts={self.current_state["counts"]}'
|
f'counts={self.current_state["counts"]}'
|
||||||
)
|
)
|
||||||
self._persist_day()
|
self._persist_day()
|
||||||
|
|
||||||
self.current_state['last_detection_time'] = datetime.now().isoformat()
|
self.current_state['last_detection_time'] = datetime.now().isoformat()
|
||||||
self.save_state()
|
self.save_state()
|
||||||
return self.current_state['count'], day_started, counted
|
return self.current_state['total_count'], day_started, counted
|
||||||
|
|
||||||
def _persist_day(self):
|
def _persist_day(self):
|
||||||
state = self.current_state
|
state = self.current_state
|
||||||
@@ -298,7 +299,7 @@ class CounterStore:
|
|||||||
""",
|
""",
|
||||||
(
|
(
|
||||||
state['counting_date'], self.camera_name, self.object_label,
|
state['counting_date'], self.camera_name, self.object_label,
|
||||||
state['count'],
|
state['total_count'],
|
||||||
state['start_time'], datetime.now().isoformat(),
|
state['start_time'], datetime.now().isoformat(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -339,7 +340,7 @@ class CounterStore:
|
|||||||
def current_count(self):
|
def current_count(self):
|
||||||
if self.current_state is None:
|
if self.current_state is None:
|
||||||
return 0
|
return 0
|
||||||
return self.current_state['count']
|
return self.current_state['total_count']
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def current_counts(self):
|
def current_counts(self):
|
||||||
|
|||||||
@@ -772,8 +772,9 @@
|
|||||||
<div class="footer">Edge Nano Counter by ZenAi</div>
|
<div class="footer">Edge Nano Counter by ZenAi</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script type="application/json" id="zones-config">{{ zones | tojson }}</script>
|
||||||
<script>
|
<script>
|
||||||
const ZONES = {{ zones | tojson }};
|
const ZONES = JSON.parse(document.getElementById('zones-config').textContent);
|
||||||
const ZONE_COLORS = [
|
const ZONE_COLORS = [
|
||||||
['rgba(0, 255, 136, 0.7)', 'rgba(0, 255, 136, 1)'],
|
['rgba(0, 255, 136, 0.7)', 'rgba(0, 255, 136, 1)'],
|
||||||
['rgba(255, 45, 120, 0.7)', 'rgba(255, 45, 120, 1)'],
|
['rgba(255, 45, 120, 0.7)', 'rgba(255, 45, 120, 1)'],
|
||||||
@@ -883,7 +884,9 @@ async function loadCurrentCounter() {
|
|||||||
if (!res.ok) throw new Error('No active counter');
|
if (!res.ok) throw new Error('No active counter');
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
const counts = data.counts || {};
|
const counts = data.counts || {};
|
||||||
const total = data.count != null ? data.count : Object.values(counts).reduce((a, b) => a + (b || 0), 0);
|
const total = data.total_count != null
|
||||||
|
? data.total_count
|
||||||
|
: Object.values(counts).reduce((a, b) => a + (b || 0), 0);
|
||||||
document.getElementById('today-count').textContent = total.toLocaleString();
|
document.getElementById('today-count').textContent = total.toLocaleString();
|
||||||
ZONES.forEach(z => {
|
ZONES.forEach(z => {
|
||||||
const el = document.getElementById('today-' + z.id);
|
const el = document.getElementById('today-' + z.id);
|
||||||
@@ -902,12 +905,16 @@ async function loadSummary() {
|
|||||||
try {
|
try {
|
||||||
const res = await fetch('/api/summary');
|
const res = await fetch('/api/summary');
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
|
if (!data || !data.today) {
|
||||||
|
console.error('Failed to load summary: unexpected payload', data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
document.getElementById('current-date').textContent = data.today.date;
|
document.getElementById('current-date').textContent = data.today.date || '--';
|
||||||
|
|
||||||
const yCounts = (data.yesterday && data.yesterday.counts) || {};
|
const yCounts = (data.yesterday && data.yesterday.counts) || {};
|
||||||
document.getElementById('yesterday-count').textContent = (
|
document.getElementById('yesterday-count').textContent = (
|
||||||
data.yesterday.total_count != null
|
data.yesterday && data.yesterday.total_count != null
|
||||||
? data.yesterday.total_count
|
? data.yesterday.total_count
|
||||||
: Object.values(yCounts).reduce((a, b) => a + (b || 0), 0)
|
: Object.values(yCounts).reduce((a, b) => a + (b || 0), 0)
|
||||||
).toLocaleString();
|
).toLocaleString();
|
||||||
@@ -916,14 +923,14 @@ async function loadSummary() {
|
|||||||
if (el) el.textContent = (yCounts[z.id] || 0).toLocaleString();
|
if (el) el.textContent = (yCounts[z.id] || 0).toLocaleString();
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById('avg-count').textContent = Number(data.average_per_day).toLocaleString();
|
document.getElementById('avg-count').textContent = Number(data.average_per_day || 0).toLocaleString();
|
||||||
document.getElementById('total-days').textContent = `${data.all_time.total_days} days recorded`;
|
document.getElementById('total-days').textContent = `${(data.all_time && data.all_time.total_days) || 0} days recorded`;
|
||||||
|
|
||||||
document.getElementById('best-count').textContent = data.best_day.count.toLocaleString();
|
document.getElementById('best-count').textContent = ((data.best_day && data.best_day.count) || 0).toLocaleString();
|
||||||
document.getElementById('best-date').textContent = data.best_day.date || '--';
|
document.getElementById('best-date').textContent = (data.best_day && data.best_day.date) || '--';
|
||||||
|
|
||||||
const gCounts = (data.all_time && data.all_time.counts) || {};
|
const gCounts = (data.all_time && data.all_time.counts) || {};
|
||||||
document.getElementById('grand-total').textContent = (data.all_time.grand_total || 0).toLocaleString();
|
document.getElementById('grand-total').textContent = ((data.all_time && data.all_time.grand_total) || 0).toLocaleString();
|
||||||
ZONES.forEach(z => {
|
ZONES.forEach(z => {
|
||||||
const el = document.getElementById('grand-' + z.id);
|
const el = document.getElementById('grand-' + z.id);
|
||||||
if (el) el.textContent = (gCounts[z.id] || 0).toLocaleString();
|
if (el) el.textContent = (gCounts[z.id] || 0).toLocaleString();
|
||||||
|
|||||||
Reference in new issue
Block a user