pumaguard 20.post157__py3-none-any.whl → 20.post161__py3-none-any.whl
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.
- pumaguard/presets.py +38 -0
- pumaguard/pumaguard-ui/flutter_bootstrap.js +1 -1
- pumaguard/pumaguard-ui/flutter_service_worker.js +1 -1
- pumaguard/server.py +26 -1
- pumaguard/utils.py +25 -3
- {pumaguard-20.post157.dist-info → pumaguard-20.post161.dist-info}/METADATA +1 -1
- {pumaguard-20.post157.dist-info → pumaguard-20.post161.dist-info}/RECORD +11 -11
- {pumaguard-20.post157.dist-info → pumaguard-20.post161.dist-info}/WHEEL +0 -0
- {pumaguard-20.post157.dist-info → pumaguard-20.post161.dist-info}/entry_points.txt +0 -0
- {pumaguard-20.post157.dist-info → pumaguard-20.post161.dist-info}/licenses/LICENSE +0 -0
- {pumaguard-20.post157.dist-info → pumaguard-20.post161.dist-info}/top_level.txt +0 -0
pumaguard/presets.py
CHANGED
|
@@ -34,6 +34,19 @@ def get_xdg_config_home() -> Path:
|
|
|
34
34
|
return Path.home() / ".config"
|
|
35
35
|
|
|
36
36
|
|
|
37
|
+
def get_xdg_data_home() -> Path:
|
|
38
|
+
"""
|
|
39
|
+
Get the XDG data home directory according to XDG Base Directory spec.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
Path to XDG_DATA_HOME (defaults to ~/.local/share if not set)
|
|
43
|
+
"""
|
|
44
|
+
xdg_data = os.environ.get("XDG_DATA_HOME")
|
|
45
|
+
if xdg_data:
|
|
46
|
+
return Path(xdg_data)
|
|
47
|
+
return Path.home() / ".local" / "share"
|
|
48
|
+
|
|
49
|
+
|
|
37
50
|
def get_default_settings_file() -> str:
|
|
38
51
|
"""
|
|
39
52
|
Get the default settings file path using XDG standards.
|
|
@@ -128,6 +141,31 @@ class Preset:
|
|
|
128
141
|
else:
|
|
129
142
|
self.tf_compat = "2.17"
|
|
130
143
|
|
|
144
|
+
# Classification product directories (XDG data location by default)
|
|
145
|
+
data_root = get_xdg_data_home() / "pumaguard"
|
|
146
|
+
self.classification_root_dir = str(data_root / "classified")
|
|
147
|
+
self.classified_puma_dir = str(
|
|
148
|
+
Path(self.classification_root_dir) / "puma"
|
|
149
|
+
)
|
|
150
|
+
self.classified_other_dir = str(
|
|
151
|
+
Path(self.classification_root_dir) / "other"
|
|
152
|
+
)
|
|
153
|
+
self.intermediate_dir = str(
|
|
154
|
+
Path(self.classification_root_dir) / "intermediate"
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
# Ensure directories exist
|
|
158
|
+
for d in [
|
|
159
|
+
self.classification_root_dir,
|
|
160
|
+
self.classified_puma_dir,
|
|
161
|
+
self.classified_other_dir,
|
|
162
|
+
self.intermediate_dir,
|
|
163
|
+
]:
|
|
164
|
+
try:
|
|
165
|
+
Path(d).mkdir(parents=True, exist_ok=True)
|
|
166
|
+
except OSError as exc: # pragma: no cover (rare failure)
|
|
167
|
+
logger.error("Could not create directory %s: %s", d, exc)
|
|
168
|
+
|
|
131
169
|
def load(self, filename: str):
|
|
132
170
|
"""
|
|
133
171
|
Load settings from YAML file.
|
|
@@ -34,7 +34,7 @@ const RESOURCES = {"flutter.js": "24bc71911b75b5f8135c949e27a2984e",
|
|
|
34
34
|
"canvaskit/skwasm.js.symbols": "3a4aadf4e8141f284bd524976b1d6bdc",
|
|
35
35
|
"favicon.png": "5dcef449791fa27946b3d35ad8803796",
|
|
36
36
|
"main.dart.wasm": "b7e85784e7cc42b937c6ddffca885d19",
|
|
37
|
-
"flutter_bootstrap.js": "
|
|
37
|
+
"flutter_bootstrap.js": "edaeca3e7e893db7d1b39e427aef8dfe",
|
|
38
38
|
"version.json": "d3ae24eea88b92d3d617cfcd1d6d057d",
|
|
39
39
|
"main.dart.js": "8d76816e4e65d2d9504d5fd4013ba7cf"};
|
|
40
40
|
// The application shell files that are downloaded before a service worker can
|
pumaguard/server.py
CHANGED
|
@@ -6,11 +6,15 @@ that the new images show pumas.
|
|
|
6
6
|
import argparse
|
|
7
7
|
import logging
|
|
8
8
|
import os
|
|
9
|
+
import shutil
|
|
9
10
|
import signal
|
|
10
11
|
import subprocess
|
|
11
12
|
import sys
|
|
12
13
|
import threading
|
|
13
14
|
import time
|
|
15
|
+
from pathlib import (
|
|
16
|
+
Path,
|
|
17
|
+
)
|
|
14
18
|
|
|
15
19
|
from PIL import (
|
|
16
20
|
Image,
|
|
@@ -257,7 +261,9 @@ class FolderObserver:
|
|
|
257
261
|
return
|
|
258
262
|
logger.debug("Classifying: %s", filepath)
|
|
259
263
|
prediction = classify_image_two_stage(
|
|
260
|
-
presets=self.presets,
|
|
264
|
+
presets=self.presets,
|
|
265
|
+
image_path=filepath,
|
|
266
|
+
intermediate_dir=self.presets.intermediate_dir,
|
|
261
267
|
)
|
|
262
268
|
logger.info("Chance of puma in %s: %.2f%%", filepath, prediction * 100)
|
|
263
269
|
if prediction > 0.5:
|
|
@@ -267,6 +273,25 @@ class FolderObserver:
|
|
|
267
273
|
self.presets.sound_path, self.presets.deterrent_sound_file
|
|
268
274
|
)
|
|
269
275
|
playsound(sound_file_path)
|
|
276
|
+
# Move original file into classification folder
|
|
277
|
+
try:
|
|
278
|
+
dest_root = (
|
|
279
|
+
self.presets.classified_puma_dir
|
|
280
|
+
if prediction > 0.5
|
|
281
|
+
else self.presets.classified_other_dir
|
|
282
|
+
)
|
|
283
|
+
Path(dest_root).mkdir(parents=True, exist_ok=True)
|
|
284
|
+
dest_path = Path(dest_root) / Path(filepath).name
|
|
285
|
+
shutil.move(filepath, dest_path)
|
|
286
|
+
logger.info(
|
|
287
|
+
"Moved %s to classification folder %s", filepath, dest_path
|
|
288
|
+
)
|
|
289
|
+
except Exception as exc: # pylint: disable=broad-except
|
|
290
|
+
logger.error(
|
|
291
|
+
"Failed to move %s into classification folder: %s",
|
|
292
|
+
filepath,
|
|
293
|
+
exc,
|
|
294
|
+
)
|
|
270
295
|
lock.release()
|
|
271
296
|
logger.debug("Exiting (%s)", me.name)
|
|
272
297
|
|
pumaguard/utils.py
CHANGED
|
@@ -410,7 +410,10 @@ def cache_model_two_stage(
|
|
|
410
410
|
|
|
411
411
|
|
|
412
412
|
def classify_image_two_stage(
|
|
413
|
-
presets: Preset,
|
|
413
|
+
presets: Preset,
|
|
414
|
+
image_path: str,
|
|
415
|
+
print_progress: bool = True,
|
|
416
|
+
intermediate_dir: str | None = None,
|
|
414
417
|
) -> float:
|
|
415
418
|
"""
|
|
416
419
|
Classify the image using two-stage approach: YOLO detection + EfficientNet
|
|
@@ -420,9 +423,16 @@ def classify_image_two_stage(
|
|
|
420
423
|
presets (Preset): An instance of the Preset class containing settings.
|
|
421
424
|
image_path (str): The file path to the image to be classified.
|
|
422
425
|
|
|
426
|
+
Args:
|
|
427
|
+
presets (Preset): Settings preset.
|
|
428
|
+
image_path (str): Path to image file.
|
|
429
|
+
print_progress (bool): Whether to print model download progress.
|
|
430
|
+
intermediate_dir (str | None): If provided, store visualization and
|
|
431
|
+
CSV summaries inside this directory instead of CWD.
|
|
432
|
+
|
|
423
433
|
Returns:
|
|
424
|
-
float: Maximum puma probability from all detections
|
|
425
|
-
detections)
|
|
434
|
+
float: Maximum puma probability from all detections
|
|
435
|
+
(0.0 if no detections)
|
|
426
436
|
"""
|
|
427
437
|
|
|
428
438
|
def expand_box(xyxy, crop_expand, width, height):
|
|
@@ -577,7 +587,10 @@ def classify_image_two_stage(
|
|
|
577
587
|
axc.set_title(f"det {idx} — {det_probs[idx]:.3f} → {lbl}")
|
|
578
588
|
idx += 1
|
|
579
589
|
|
|
590
|
+
# Determine output paths
|
|
580
591
|
out_png = f"{image_file.stem}_viz.png"
|
|
592
|
+
if intermediate_dir:
|
|
593
|
+
out_png = str(Path(intermediate_dir) / out_png)
|
|
581
594
|
plt.tight_layout()
|
|
582
595
|
plt.savefig(out_png, dpi=160)
|
|
583
596
|
plt.close(fig)
|
|
@@ -616,8 +629,17 @@ def classify_image_two_stage(
|
|
|
616
629
|
)
|
|
617
630
|
|
|
618
631
|
# Write CSV outputs
|
|
632
|
+
# Per-image CSV names (avoid overwriting)
|
|
619
633
|
det_csv = "test_detections_predictions.csv"
|
|
620
634
|
img_csv = "test_image_summary.csv"
|
|
635
|
+
if intermediate_dir:
|
|
636
|
+
det_csv = str(
|
|
637
|
+
Path(intermediate_dir)
|
|
638
|
+
/ f"{image_file.stem}_detections_predictions.csv"
|
|
639
|
+
)
|
|
640
|
+
img_csv = str(
|
|
641
|
+
Path(intermediate_dir) / f"{image_file.stem}_image_summary.csv"
|
|
642
|
+
)
|
|
621
643
|
|
|
622
644
|
# Write detection predictions CSV
|
|
623
645
|
if all_rows:
|
|
@@ -5,11 +5,11 @@ pumaguard/main.py,sha256=_dxt9P_SNIoFJA6HqU9KGeC9519c7CN4CA8_D-gPyEQ,6284
|
|
|
5
5
|
pumaguard/model-registry.yaml,sha256=V-pTaqJrk_jJo568okBDaVhs51qTHttSqKe6PqdX6Bc,10318
|
|
6
6
|
pumaguard/model_cli.py,sha256=nzDv0lXSvRKpLxs579tiHInJPPV-AFO4jzeLk5t2GaA,1394
|
|
7
7
|
pumaguard/model_downloader.py,sha256=dymLuHAeIETALNouBG2KlLxUcxZNJ1lOQv5v9-V7_lk,12078
|
|
8
|
-
pumaguard/presets.py,sha256=
|
|
9
|
-
pumaguard/server.py,sha256=
|
|
8
|
+
pumaguard/presets.py,sha256=T8-GsqWrOCnwwT6Fu2WWCf46pyhudQcgps4XqtGtEgE,25795
|
|
9
|
+
pumaguard/server.py,sha256=UcD7KYviWvetZy-wU8KcH6mTLR2Kj-s8bxDm2byCj1I,13168
|
|
10
10
|
pumaguard/sound.py,sha256=dBylHyuS8ro9tFJH5y3s6Bn2kSGnfrOyGeGYZlgYTsU,369
|
|
11
11
|
pumaguard/stats.py,sha256=ZwocfnFCQ-ky7me-YTTrEoJqsIHOWAgSzeoJHItsIU4,927
|
|
12
|
-
pumaguard/utils.py,sha256=
|
|
12
|
+
pumaguard/utils.py,sha256=w1EgOLSZGyjq_b49hvVZhBESy-lVP0yRtNHe-sXBoIU,19735
|
|
13
13
|
pumaguard/verify.py,sha256=vfw3PRzDt1uuH5FKV9F5vb1PH7KQ6AEgVNhJ6jck_hQ,5513
|
|
14
14
|
pumaguard/web_ui.py,sha256=E_cEV3cA1srlwMXc3eFQW6UiNE1BKd0oJlKIoduARSI,34761
|
|
15
15
|
pumaguard/completions/pumaguard-classify-completions.sh,sha256=5QySg-2Jdinj15qpUYa5UzHbTgYzi2gmPVYYyyXny4c,1353
|
|
@@ -19,8 +19,8 @@ pumaguard/completions/pumaguard-train-completions.sh,sha256=lI8LG-QrncvhUqCeKtfr
|
|
|
19
19
|
pumaguard/pumaguard-ui/.last_build_id,sha256=2z9bkdHZlfzXSpHBHs18Lo4GUD8oTSkZDZxqAeZW6KE,32
|
|
20
20
|
pumaguard/pumaguard-ui/favicon.png,sha256=erJSX0uGtl0-THA1ihfloar29Df5nLzARtrXPVm7kBU,917
|
|
21
21
|
pumaguard/pumaguard-ui/flutter.js,sha256=7V1ZIKmGiouT15CpquQWWmKWJyjUq77FoU9gDXPFO9M,9412
|
|
22
|
-
pumaguard/pumaguard-ui/flutter_bootstrap.js,sha256=
|
|
23
|
-
pumaguard/pumaguard-ui/flutter_service_worker.js,sha256=
|
|
22
|
+
pumaguard/pumaguard-ui/flutter_bootstrap.js,sha256=rm6PkXnfIAfcDQu4GPY-nECkUSec9Xbe4Jgq7Adl19c,9858
|
|
23
|
+
pumaguard/pumaguard-ui/flutter_service_worker.js,sha256=6c7y6iuuFQjmBV3odLYhmnHfhz-PzChJ8WchuXE5kCQ,8435
|
|
24
24
|
pumaguard/pumaguard-ui/index.html,sha256=901-ZY0WysVAZWPwj2xGatoezwm9TX9IV_jpMrlsaXg,1205
|
|
25
25
|
pumaguard/pumaguard-ui/main.dart.js,sha256=fFz7OvGMIyrSvIBcp1jK3P3x1xCh3i3anBpMHuaVgDo,2613988
|
|
26
26
|
pumaguard/pumaguard-ui/main.dart.mjs,sha256=u8D9JVFd7gNLKK-L2s_IjAfLkymktS1DXV25sXo4BsQ,33768
|
|
@@ -51,7 +51,7 @@ pumaguard/pumaguard-ui/icons/Icon-192.png,sha256=Pc6ZB3YC9wQhwcayokC8m4PWTYZoHUX
|
|
|
51
51
|
pumaguard/pumaguard-ui/icons/Icon-512.png,sha256=usyyBa5F8LQhvhZXJZtJQ6xAyVCUq4d_O8vhLNVE3L4,8252
|
|
52
52
|
pumaguard/pumaguard-ui/icons/Icon-maskable-192.png,sha256=0shC4iqfTsnZlrIzc6kFyI2aIDsiDFwVGIWtYh-XS1w,5594
|
|
53
53
|
pumaguard/pumaguard-ui/icons/Icon-maskable-512.png,sha256=au4Gzcq2sq73Sxc0xHePRCHS2hALD_nlKyG1UkAgKSk,20998
|
|
54
|
-
pumaguard-20.
|
|
54
|
+
pumaguard-20.post161.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
55
55
|
pumaguard-sounds/cougar_call.mp3,sha256=jdPzi7Qneect3ez2G6XAeHWtetU5vSOSB6pceuB26Wc,129048
|
|
56
56
|
pumaguard-sounds/cougarsounds.wav,sha256=hwVmmQ75dkOP3qd07YAvVOSm1neYtxLSzxw3Ulvs2cM,96346
|
|
57
57
|
pumaguard-sounds/dark-engine-logo-141942.mp3,sha256=Vw-qyLTMPJZvsgQcZtH0DpGcP1dd7nJq-9BnHuNPGug,372819
|
|
@@ -69,8 +69,8 @@ pumaguard-sounds/mixkit-vintage-telephone-ringtone-1356.wav,sha256=zWWY2uFF0-l7P
|
|
|
69
69
|
pumaguard-sounds/pumaguard-warning.mp3,sha256=wcCfHsulPo5P5s8MjpQAG2NYHQDsRpjqoMig1-o_MDI,232249
|
|
70
70
|
pumaguard-sounds/short-round-110940.mp3,sha256=vdskGD94SeH1UJyJyR0Ek_7xGXPIZfnPdoBvxGnUt98,450816
|
|
71
71
|
pumaguard-ui/ios/Flutter/ephemeral/flutter_lldb_helper.py,sha256=Bc_jl3_e5ZPvrSBJpPYtN05VxpztyKq-7lVms3rLg4Q,1276
|
|
72
|
-
pumaguard-20.
|
|
73
|
-
pumaguard-20.
|
|
74
|
-
pumaguard-20.
|
|
75
|
-
pumaguard-20.
|
|
76
|
-
pumaguard-20.
|
|
72
|
+
pumaguard-20.post161.dist-info/METADATA,sha256=-CEFH-8_EK4ubTVF1USB9UIbO8gbx-D2k2CIQtlm4VM,7751
|
|
73
|
+
pumaguard-20.post161.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
74
|
+
pumaguard-20.post161.dist-info/entry_points.txt,sha256=rmCdBTPWrbJQvPPwABSVobXE9D7hrKsITGZ6nvCrko8,127
|
|
75
|
+
pumaguard-20.post161.dist-info/top_level.txt,sha256=B-PzS4agkQNhOYbLLIrMVOyMD_pl5F-yujPBm5zYYjY,40
|
|
76
|
+
pumaguard-20.post161.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|