birdnet-analyzer 2.0.1__py3-none-any.whl → 2.1.0__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.
- birdnet_analyzer/analyze/__init__.py +14 -0
- birdnet_analyzer/analyze/cli.py +5 -0
- birdnet_analyzer/analyze/core.py +6 -1
- birdnet_analyzer/analyze/utils.py +42 -40
- birdnet_analyzer/audio.py +2 -2
- birdnet_analyzer/cli.py +41 -18
- birdnet_analyzer/config.py +4 -3
- birdnet_analyzer/eBird_taxonomy_codes_2024E.json +13046 -0
- birdnet_analyzer/embeddings/core.py +2 -1
- birdnet_analyzer/embeddings/utils.py +42 -1
- birdnet_analyzer/evaluation/__init__.py +6 -13
- birdnet_analyzer/evaluation/assessment/performance_assessor.py +12 -57
- birdnet_analyzer/evaluation/assessment/plotting.py +61 -62
- birdnet_analyzer/evaluation/preprocessing/data_processor.py +1 -1
- birdnet_analyzer/gui/analysis.py +5 -1
- birdnet_analyzer/gui/assets/gui.css +8 -0
- birdnet_analyzer/gui/embeddings.py +37 -18
- birdnet_analyzer/gui/evaluation.py +14 -8
- birdnet_analyzer/gui/multi_file.py +25 -5
- birdnet_analyzer/gui/review.py +16 -63
- birdnet_analyzer/gui/settings.py +25 -4
- birdnet_analyzer/gui/single_file.py +14 -17
- birdnet_analyzer/gui/train.py +7 -16
- birdnet_analyzer/gui/utils.py +42 -55
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_ca.txt +1 -1
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_pl.txt +1 -1
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_sr.txt +108 -108
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_zh.txt +1 -1
- birdnet_analyzer/lang/de.json +7 -0
- birdnet_analyzer/lang/en.json +7 -0
- birdnet_analyzer/lang/fi.json +7 -0
- birdnet_analyzer/lang/fr.json +7 -0
- birdnet_analyzer/lang/id.json +7 -0
- birdnet_analyzer/lang/pt-br.json +7 -0
- birdnet_analyzer/lang/ru.json +36 -29
- birdnet_analyzer/lang/se.json +7 -0
- birdnet_analyzer/lang/tlh.json +7 -0
- birdnet_analyzer/lang/zh_TW.json +7 -0
- birdnet_analyzer/model.py +21 -21
- birdnet_analyzer/search/core.py +1 -1
- birdnet_analyzer/utils.py +3 -4
- {birdnet_analyzer-2.0.1.dist-info → birdnet_analyzer-2.1.0.dist-info}/METADATA +18 -9
- {birdnet_analyzer-2.0.1.dist-info → birdnet_analyzer-2.1.0.dist-info}/RECORD +47 -47
- {birdnet_analyzer-2.0.1.dist-info → birdnet_analyzer-2.1.0.dist-info}/WHEEL +1 -1
- birdnet_analyzer/eBird_taxonomy_codes_2021E.json +0 -25280
- {birdnet_analyzer-2.0.1.dist-info → birdnet_analyzer-2.1.0.dist-info}/entry_points.txt +0 -0
- {birdnet_analyzer-2.0.1.dist-info → birdnet_analyzer-2.1.0.dist-info}/licenses/LICENSE +0 -0
- {birdnet_analyzer-2.0.1.dist-info → birdnet_analyzer-2.1.0.dist-info}/top_level.txt +0 -0
birdnet_analyzer/gui/train.py
CHANGED
@@ -9,6 +9,7 @@ import birdnet_analyzer.config as cfg
|
|
9
9
|
import birdnet_analyzer.gui.localization as loc
|
10
10
|
import birdnet_analyzer.gui.utils as gu
|
11
11
|
from birdnet_analyzer import utils
|
12
|
+
from birdnet_analyzer.gui.settings import APPDIR
|
12
13
|
|
13
14
|
_GRID_MAX_HEIGHT = 240
|
14
15
|
|
@@ -198,16 +199,14 @@ def start_training(
|
|
198
199
|
|
199
200
|
def trial_progression(trial):
|
200
201
|
if progress is not None:
|
201
|
-
progress(
|
202
|
-
(trial, autotune_trials), total=autotune_trials, unit="trials", desc=loc.localize("progress-autotune")
|
203
|
-
)
|
202
|
+
progress((trial, autotune_trials), total=autotune_trials, unit="trials", desc=loc.localize("progress-autotune"))
|
204
203
|
|
205
204
|
try:
|
206
205
|
history_result = train_model(
|
207
206
|
on_epoch_end=epoch_progression,
|
208
207
|
on_trial_result=trial_progression,
|
209
208
|
on_data_load_end=data_load_progression,
|
210
|
-
autotune_directory=
|
209
|
+
autotune_directory=APPDIR if utils.FROZEN else "autotune",
|
211
210
|
)
|
212
211
|
|
213
212
|
# Unpack history and metrics
|
@@ -315,9 +314,7 @@ def build_train_tab():
|
|
315
314
|
info=loc.localize("training-tab-cache-mode-radio-info"),
|
316
315
|
)
|
317
316
|
with gr.Column(visible=False) as new_cache_file_row:
|
318
|
-
select_cache_file_directory_btn = gr.Button(
|
319
|
-
loc.localize("training-tab-cache-select-directory-button-label")
|
320
|
-
)
|
317
|
+
select_cache_file_directory_btn = gr.Button(loc.localize("training-tab-cache-select-directory-button-label"))
|
321
318
|
|
322
319
|
with gr.Column():
|
323
320
|
cache_file_name = gr.Textbox(
|
@@ -426,9 +423,7 @@ def build_train_tab():
|
|
426
423
|
|
427
424
|
def on_crop_select(new_crop_mode):
|
428
425
|
# Make overlap slider visible for both "segments" and "smart" crop modes
|
429
|
-
return gr.Number(
|
430
|
-
visible=new_crop_mode in ["segments", "smart"], interactive=new_crop_mode in ["segments", "smart"]
|
431
|
-
)
|
426
|
+
return gr.Number(visible=new_crop_mode in ["segments", "smart"], interactive=new_crop_mode in ["segments", "smart"])
|
432
427
|
|
433
428
|
crop_mode.change(on_crop_select, inputs=crop_mode, outputs=crop_overlap)
|
434
429
|
|
@@ -576,9 +571,7 @@ def build_train_tab():
|
|
576
571
|
def on_focal_loss_change(value):
|
577
572
|
return gr.Row(visible=value)
|
578
573
|
|
579
|
-
use_focal_loss.change(
|
580
|
-
on_focal_loss_change, inputs=use_focal_loss, outputs=focal_loss_params, show_progress=False
|
581
|
-
)
|
574
|
+
use_focal_loss.change(on_focal_loss_change, inputs=use_focal_loss, outputs=focal_loss_params, show_progress=False)
|
582
575
|
|
583
576
|
def on_autotune_change(value):
|
584
577
|
return (
|
@@ -610,9 +603,7 @@ def build_train_tab():
|
|
610
603
|
visible=False,
|
611
604
|
label="Model Performance Metrics (Default Threshold 0.5)",
|
612
605
|
)
|
613
|
-
start_training_button = gr.Button(
|
614
|
-
loc.localize("training-tab-start-training-button-label"), variant="huggingface"
|
615
|
-
)
|
606
|
+
start_training_button = gr.Button(loc.localize("training-tab-start-training-button-label"), variant="huggingface")
|
616
607
|
|
617
608
|
def train_and_show_metrics(*args):
|
618
609
|
history, metrics = start_training(*args)
|
birdnet_analyzer/gui/utils.py
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
# ruff: noqa: PLW0603
|
2
|
+
import base64
|
3
|
+
import io
|
2
4
|
import multiprocessing
|
3
5
|
import os
|
4
6
|
import sys
|
@@ -10,27 +12,8 @@ import gradio as gr
|
|
10
12
|
import webview
|
11
13
|
|
12
14
|
import birdnet_analyzer.config as cfg
|
13
|
-
from birdnet_analyzer import utils
|
14
|
-
|
15
|
-
if utils.FROZEN:
|
16
|
-
# divert stdout & stderr to logs.txt file since we have no console when deployed
|
17
|
-
userdir = Path.home()
|
18
|
-
|
19
|
-
if sys.platform == "win32":
|
20
|
-
userdir /= "AppData/Roaming"
|
21
|
-
elif sys.platform == "linux":
|
22
|
-
userdir /= ".local/share"
|
23
|
-
elif sys.platform == "darwin":
|
24
|
-
userdir /= "Library/Application Support"
|
25
|
-
|
26
|
-
APPDIR = userdir / "BirdNET-Analyzer-GUI"
|
27
|
-
|
28
|
-
APPDIR.mkdir(parents=True, exist_ok=True)
|
29
|
-
|
30
|
-
sys.stderr = sys.stdout = open(str(APPDIR / "logs.txt"), "a") # noqa: SIM115
|
31
|
-
cfg.ERROR_LOG_FILE = str(APPDIR / os.path.basename(cfg.ERROR_LOG_FILE))
|
32
|
-
|
33
15
|
import birdnet_analyzer.gui.localization as loc
|
16
|
+
from birdnet_analyzer import utils
|
34
17
|
from birdnet_analyzer.gui import settings
|
35
18
|
|
36
19
|
loc.load_local_state()
|
@@ -41,11 +24,12 @@ _CUSTOM_SPECIES = loc.localize("species-list-radio-option-custom-list")
|
|
41
24
|
_PREDICT_SPECIES = loc.localize("species-list-radio-option-predict-list")
|
42
25
|
_CUSTOM_CLASSIFIER = loc.localize("species-list-radio-option-custom-classifier")
|
43
26
|
_ALL_SPECIES = loc.localize("species-list-radio-option-all")
|
44
|
-
_WINDOW: webview.Window = None
|
27
|
+
_WINDOW: webview.Window | None = None
|
45
28
|
_URL = ""
|
29
|
+
_HEART_LOGO = "data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjE2IiB2aWV3Qm94PSIwIDAgMTYgMTYiIHZlcnNpb249IjEuMSIgd2lkdGg9IjE2IiBkYXRhLXZpZXctY29tcG9uZW50PSJ0cnVlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPg0KICAgIDxwYXRoIGQ9Im04IDE0LjI1LjM0NS42NjZhLjc1Ljc1IDAgMCAxLS42OSAwbC0uMDA4LS4wMDQtLjAxOC0uMDFhNy4xNTIgNy4xNTIgMCAwIDEtLjMxLS4xNyAyMi4wNTUgMjIuMDU1IDAgMCAxLTMuNDM0LTIuNDE0QzIuMDQ1IDEwLjczMSAwIDguMzUgMCA1LjUgMCAyLjgzNiAyLjA4NiAxIDQuMjUgMSA1Ljc5NyAxIDcuMTUzIDEuODAyIDggMy4wMiA4Ljg0NyAxLjgwMiAxMC4yMDMgMSAxMS43NSAxIDEzLjkxNCAxIDE2IDIuODM2IDE2IDUuNWMwIDIuODUtMi4wNDUgNS4yMzEtMy44ODUgNi44MThhMjIuMDY2IDIyLjA2NiAwIDAgMS0zLjc0NCAyLjU4NGwtLjAxOC4wMS0uMDA2LjAwM2gtLjAwMlpNNC4yNSAyLjVjLTEuMzM2IDAtMi43NSAxLjE2NC0yLjc1IDMgMCAyLjE1IDEuNTggNC4xNDQgMy4zNjUgNS42ODJBMjAuNTggMjAuNTggMCAwIDAgOCAxMy4zOTNhMjAuNTggMjAuNTggMCAwIDAgMy4xMzUtMi4yMTFDMTIuOTIgOS42NDQgMTQuNSA3LjY1IDE0LjUgNS41YzAtMS44MzYtMS40MTQtMy0yLjc1LTMtMS4zNzMgMC0yLjYwOS45ODYtMy4wMjkgMi40NTZhLjc0OS43NDkgMCAwIDEtMS40NDIgMEM2Ljg1OSAzLjQ4NiA1LjYyMyAyLjUgNC4yNSAyLjVaIj48L3BhdGg+DQo8L3N2Zz4=" # noqa: E501
|
46
30
|
|
47
31
|
|
48
|
-
def gui_runtime_error_handler(f
|
32
|
+
def gui_runtime_error_handler(f):
|
49
33
|
"""
|
50
34
|
A decorator function to handle errors during the execution of a callable.
|
51
35
|
|
@@ -196,9 +180,7 @@ def select_directory(collect_files=True, max_files=None, state_key=None):
|
|
196
180
|
|
197
181
|
files = utils.collect_audio_files(dir_name, max_files=max_files)
|
198
182
|
|
199
|
-
return dir_name, [
|
200
|
-
[os.path.relpath(file, dir_name), format_seconds(librosa.get_duration(filename=file))] for file in files
|
201
|
-
]
|
183
|
+
return dir_name, [[os.path.relpath(file, dir_name), format_seconds(librosa.get_duration(filename=file))] for file in files]
|
202
184
|
|
203
185
|
return dir_name if dir_name else None
|
204
186
|
|
@@ -228,9 +210,12 @@ def build_footer():
|
|
228
210
|
<div>Model version: {cfg.MODEL_VERSION}</div>
|
229
211
|
</div>
|
230
212
|
<div>K. Lisa Yang Center for Conservation Bioacoustics<br>Chemnitz University of Technology</div>
|
231
|
-
<div>{loc.localize("footer-help")}
|
232
|
-
target='_blank'>birdnet.cornell.edu/analyzer</a
|
233
|
-
|
213
|
+
<div>{loc.localize("footer-help")}: <a href='https://birdnet.cornell.edu/analyzer'
|
214
|
+
target='_blank'>birdnet.cornell.edu/analyzer</a>
|
215
|
+
<br><img id='heart' src='{_HEART_LOGO}'>{loc.localize("footer-support")}: <a href='https://birdnet.cornell.edu/donate' target='_blank'>birdnet.cornell.edu/donate</a>
|
216
|
+
</div>
|
217
|
+
|
218
|
+
</div>""" # noqa: E501
|
234
219
|
)
|
235
220
|
|
236
221
|
|
@@ -417,9 +402,7 @@ def locale():
|
|
417
402
|
The dropdown element.
|
418
403
|
"""
|
419
404
|
label_files = os.listdir(ORIGINAL_TRANSLATED_LABELS_PATH)
|
420
|
-
options = ["EN"] + [
|
421
|
-
label_file.split("BirdNET_GLOBAL_6K_V2.4_Labels_", 1)[1].split(".txt")[0].upper() for label_file in label_files
|
422
|
-
]
|
405
|
+
options = ["EN"] + [label_file.split("BirdNET_GLOBAL_6K_V2.4_Labels_", 1)[1].split(".txt")[0].upper() for label_file in label_files]
|
423
406
|
|
424
407
|
return gr.Dropdown(
|
425
408
|
options,
|
@@ -460,18 +443,12 @@ def species_list_coordinates(show_map=False):
|
|
460
443
|
|
461
444
|
map_plot = gr.Plot(plot_map_scatter_mapbox(0, 0), show_label=False, scale=2, visible=show_map)
|
462
445
|
|
463
|
-
lat_number.change(
|
464
|
-
|
465
|
-
)
|
466
|
-
lon_number.change(
|
467
|
-
plot_map_scatter_mapbox, inputs=[lat_number, lon_number], outputs=map_plot, show_progress=False
|
468
|
-
)
|
446
|
+
lat_number.change(plot_map_scatter_mapbox, inputs=[lat_number, lon_number], outputs=map_plot, show_progress=False)
|
447
|
+
lon_number.change(plot_map_scatter_mapbox, inputs=[lat_number, lon_number], outputs=map_plot, show_progress=False)
|
469
448
|
|
470
449
|
with gr.Group():
|
471
450
|
with gr.Row():
|
472
|
-
yearlong_checkbox = gr.Checkbox(
|
473
|
-
True, label=loc.localize("species-list-coordinates-yearlong-checkbox-label")
|
474
|
-
)
|
451
|
+
yearlong_checkbox = gr.Checkbox(True, label=loc.localize("species-list-coordinates-yearlong-checkbox-label"))
|
475
452
|
week_number = gr.Slider(
|
476
453
|
minimum=1,
|
477
454
|
maximum=48,
|
@@ -509,9 +486,7 @@ def save_file_dialog(filetypes=(), state_key=None, default_filename=""):
|
|
509
486
|
The selected file or None of the dialog was canceled.
|
510
487
|
"""
|
511
488
|
initial_selection = settings.get_state(state_key, "") if state_key else ""
|
512
|
-
file = _WINDOW.create_file_dialog(
|
513
|
-
webview.SAVE_DIALOG, file_types=filetypes, directory=initial_selection, save_filename=default_filename
|
514
|
-
)
|
489
|
+
file = _WINDOW.create_file_dialog(webview.SAVE_DIALOG, file_types=filetypes, directory=initial_selection, save_filename=default_filename)
|
515
490
|
|
516
491
|
if file:
|
517
492
|
if state_key:
|
@@ -608,19 +583,13 @@ def species_lists(opened=True):
|
|
608
583
|
)
|
609
584
|
|
610
585
|
with gr.Column(visible=False) as position_row:
|
611
|
-
lat_number, lon_number, week_number, sf_thresh_number, yearlong_checkbox, map_plot = (
|
612
|
-
species_list_coordinates()
|
613
|
-
)
|
586
|
+
lat_number, lon_number, week_number, sf_thresh_number, yearlong_checkbox, map_plot = species_list_coordinates()
|
614
587
|
|
615
|
-
species_file_input = gr.File(
|
616
|
-
file_types=[".txt"], visible=False, label=loc.localize("species-list-custom-list-file-label")
|
617
|
-
)
|
588
|
+
species_file_input = gr.File(file_types=[".txt"], visible=False, label=loc.localize("species-list-custom-list-file-label"))
|
618
589
|
empty_col = gr.Column()
|
619
590
|
|
620
591
|
with gr.Column(visible=False) as custom_classifier_selector:
|
621
|
-
classifier_selection_button = gr.Button(
|
622
|
-
loc.localize("species-list-custom-classifier-selection-button-label")
|
623
|
-
)
|
592
|
+
classifier_selection_button = gr.Button(loc.localize("species-list-custom-classifier-selection-button-label"))
|
624
593
|
classifier_file_input = gr.Files(file_types=[".tflite"], visible=False, interactive=False)
|
625
594
|
selected_classifier_state = gr.State()
|
626
595
|
|
@@ -663,6 +632,26 @@ def species_lists(opened=True):
|
|
663
632
|
)
|
664
633
|
|
665
634
|
|
635
|
+
def download_plot(plot, filename=""):
|
636
|
+
from PIL import Image
|
637
|
+
|
638
|
+
imgdata = base64.b64decode(plot.plot.split(",", 1)[1])
|
639
|
+
res = _WINDOW.create_file_dialog(
|
640
|
+
webview.SAVE_DIALOG,
|
641
|
+
file_types=("PNG (*.png)", "Webp (*.webp)", "JPG (*.jpg)"),
|
642
|
+
save_filename=filename,
|
643
|
+
)
|
644
|
+
|
645
|
+
if res:
|
646
|
+
if res.endswith(".webp"):
|
647
|
+
with open(res, "wb") as f:
|
648
|
+
f.write(imgdata)
|
649
|
+
else:
|
650
|
+
output_format = res.rsplit(".", 1)[-1].upper()
|
651
|
+
img = Image.open(io.BytesIO(imgdata))
|
652
|
+
img.save(res, output_format if output_format in ["PNG", "JPEG"] else "PNG")
|
653
|
+
|
654
|
+
|
666
655
|
def _get_network_shortcuts():
|
667
656
|
"""
|
668
657
|
Retrieves a list of network shortcut paths from the user's Network Shortcuts folder.
|
@@ -696,9 +685,7 @@ def _get_network_shortcuts():
|
|
696
685
|
try:
|
697
686
|
# https://learn.microsoft.com/de-de/windows/win32/shell/links
|
698
687
|
# CLSID_ShellLink: Class ID for Shell Link object
|
699
|
-
shell_link = pythoncom.CoCreateInstance(
|
700
|
-
shell.CLSID_ShellLink, None, pythoncom.CLSCTX_INPROC_SERVER, shell.IID_IShellLink
|
701
|
-
)
|
688
|
+
shell_link = pythoncom.CoCreateInstance(shell.CLSID_ShellLink, None, pythoncom.CLSCTX_INPROC_SERVER, shell.IID_IShellLink)
|
702
689
|
|
703
690
|
# https://learn.microsoft.com/de-de/windows/win32/api/objidl/nn-objidl-ipersistfile
|
704
691
|
# Query IPersistFile interface used to
|
@@ -3211,7 +3211,7 @@ Lichenostomus cratitius_Menjamel de Boqueres
|
|
3211
3211
|
Lichenostomus melanops_Menjamel Crestagroc
|
3212
3212
|
Lichmera incana_Menjamel d'Orelles Grises
|
3213
3213
|
Lichmera indistincta_Menjamel Bru
|
3214
|
-
Lichmera
|
3214
|
+
Lichmera limbata_Indonesian Honeyeater
|
3215
3215
|
Lichmera squamata_Menjamel Escatós
|
3216
3216
|
Limnoctites rectirostris_Jonquer Becdret
|
3217
3217
|
Limnoctites sulphuriferus_Cuaespinós Gorjagroc
|
@@ -3211,7 +3211,7 @@ Lichenostomus cratitius_eukaliptusowczyk purpurowy
|
|
3211
3211
|
Lichenostomus melanops_eukaliptusowczyk żółtoczelny
|
3212
3212
|
Lichmera incana_miodojadek szarouchy
|
3213
3213
|
Lichmera indistincta_miodojadek brązowy
|
3214
|
-
Lichmera
|
3214
|
+
Lichmera limbata_Indonesian Honeyeater
|
3215
3215
|
Lichmera squamata_miodojadek łuskowany
|
3216
3216
|
Limnoctites rectirostris_szydłodziobek
|
3217
3217
|
Limnoctites sulphuriferus_moczarnik żółtogardy
|