birdnet-analyzer 2.0.0__py3-none-any.whl → 2.0.1__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.
Files changed (122) hide show
  1. birdnet_analyzer/__init__.py +9 -8
  2. birdnet_analyzer/analyze/__init__.py +5 -5
  3. birdnet_analyzer/analyze/__main__.py +3 -4
  4. birdnet_analyzer/analyze/cli.py +25 -25
  5. birdnet_analyzer/analyze/core.py +241 -245
  6. birdnet_analyzer/analyze/utils.py +692 -701
  7. birdnet_analyzer/audio.py +368 -372
  8. birdnet_analyzer/cli.py +709 -707
  9. birdnet_analyzer/config.py +242 -242
  10. birdnet_analyzer/eBird_taxonomy_codes_2021E.json +25279 -25279
  11. birdnet_analyzer/embeddings/__init__.py +3 -4
  12. birdnet_analyzer/embeddings/__main__.py +3 -3
  13. birdnet_analyzer/embeddings/cli.py +12 -13
  14. birdnet_analyzer/embeddings/core.py +69 -70
  15. birdnet_analyzer/embeddings/utils.py +179 -193
  16. birdnet_analyzer/evaluation/__init__.py +196 -195
  17. birdnet_analyzer/evaluation/__main__.py +3 -3
  18. birdnet_analyzer/evaluation/assessment/__init__.py +0 -0
  19. birdnet_analyzer/evaluation/assessment/metrics.py +388 -0
  20. birdnet_analyzer/evaluation/assessment/performance_assessor.py +409 -0
  21. birdnet_analyzer/evaluation/assessment/plotting.py +379 -0
  22. birdnet_analyzer/evaluation/preprocessing/__init__.py +0 -0
  23. birdnet_analyzer/evaluation/preprocessing/data_processor.py +631 -0
  24. birdnet_analyzer/evaluation/preprocessing/utils.py +98 -0
  25. birdnet_analyzer/gui/__init__.py +19 -23
  26. birdnet_analyzer/gui/__main__.py +3 -3
  27. birdnet_analyzer/gui/analysis.py +175 -174
  28. birdnet_analyzer/gui/assets/arrow_down.svg +4 -4
  29. birdnet_analyzer/gui/assets/arrow_left.svg +4 -4
  30. birdnet_analyzer/gui/assets/arrow_right.svg +4 -4
  31. birdnet_analyzer/gui/assets/arrow_up.svg +4 -4
  32. birdnet_analyzer/gui/assets/gui.css +28 -28
  33. birdnet_analyzer/gui/assets/gui.js +93 -93
  34. birdnet_analyzer/gui/embeddings.py +619 -620
  35. birdnet_analyzer/gui/evaluation.py +795 -813
  36. birdnet_analyzer/gui/localization.py +75 -68
  37. birdnet_analyzer/gui/multi_file.py +245 -246
  38. birdnet_analyzer/gui/review.py +519 -527
  39. birdnet_analyzer/gui/segments.py +191 -191
  40. birdnet_analyzer/gui/settings.py +128 -129
  41. birdnet_analyzer/gui/single_file.py +267 -269
  42. birdnet_analyzer/gui/species.py +95 -95
  43. birdnet_analyzer/gui/train.py +696 -698
  44. birdnet_analyzer/gui/utils.py +810 -808
  45. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_af.txt +6522 -6522
  46. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_ar.txt +6522 -6522
  47. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_bg.txt +6522 -6522
  48. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_ca.txt +6522 -6522
  49. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_cs.txt +6522 -6522
  50. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_da.txt +6522 -6522
  51. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_de.txt +6522 -6522
  52. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_el.txt +6522 -6522
  53. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_en_uk.txt +6522 -6522
  54. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_es.txt +6522 -6522
  55. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_fi.txt +6522 -6522
  56. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_fr.txt +6522 -6522
  57. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_he.txt +6522 -6522
  58. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_hr.txt +6522 -6522
  59. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_hu.txt +6522 -6522
  60. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_in.txt +6522 -6522
  61. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_is.txt +6522 -6522
  62. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_it.txt +6522 -6522
  63. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_ja.txt +6522 -6522
  64. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_ko.txt +6522 -6522
  65. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_lt.txt +6522 -6522
  66. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_ml.txt +6522 -6522
  67. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_nl.txt +6522 -6522
  68. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_no.txt +6522 -6522
  69. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_pl.txt +6522 -6522
  70. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_pt_BR.txt +6522 -6522
  71. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_pt_PT.txt +6522 -6522
  72. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_ro.txt +6522 -6522
  73. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_ru.txt +6522 -6522
  74. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_sk.txt +6522 -6522
  75. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_sl.txt +6522 -6522
  76. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_sr.txt +6522 -6522
  77. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_sv.txt +6522 -6522
  78. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_th.txt +6522 -6522
  79. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_tr.txt +6522 -6522
  80. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_uk.txt +6522 -6522
  81. birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_zh.txt +6522 -6522
  82. birdnet_analyzer/lang/de.json +334 -334
  83. birdnet_analyzer/lang/en.json +334 -334
  84. birdnet_analyzer/lang/fi.json +334 -334
  85. birdnet_analyzer/lang/fr.json +334 -334
  86. birdnet_analyzer/lang/id.json +334 -334
  87. birdnet_analyzer/lang/pt-br.json +334 -334
  88. birdnet_analyzer/lang/ru.json +334 -334
  89. birdnet_analyzer/lang/se.json +334 -334
  90. birdnet_analyzer/lang/tlh.json +334 -334
  91. birdnet_analyzer/lang/zh_TW.json +334 -334
  92. birdnet_analyzer/model.py +1212 -1243
  93. birdnet_analyzer/playground.py +5 -0
  94. birdnet_analyzer/search/__init__.py +3 -3
  95. birdnet_analyzer/search/__main__.py +3 -3
  96. birdnet_analyzer/search/cli.py +11 -12
  97. birdnet_analyzer/search/core.py +78 -78
  98. birdnet_analyzer/search/utils.py +107 -111
  99. birdnet_analyzer/segments/__init__.py +3 -3
  100. birdnet_analyzer/segments/__main__.py +3 -3
  101. birdnet_analyzer/segments/cli.py +13 -14
  102. birdnet_analyzer/segments/core.py +81 -78
  103. birdnet_analyzer/segments/utils.py +383 -394
  104. birdnet_analyzer/species/__init__.py +3 -3
  105. birdnet_analyzer/species/__main__.py +3 -3
  106. birdnet_analyzer/species/cli.py +13 -14
  107. birdnet_analyzer/species/core.py +35 -35
  108. birdnet_analyzer/species/utils.py +74 -75
  109. birdnet_analyzer/train/__init__.py +3 -3
  110. birdnet_analyzer/train/__main__.py +3 -3
  111. birdnet_analyzer/train/cli.py +13 -14
  112. birdnet_analyzer/train/core.py +113 -113
  113. birdnet_analyzer/train/utils.py +877 -847
  114. birdnet_analyzer/translate.py +133 -104
  115. birdnet_analyzer/utils.py +426 -419
  116. {birdnet_analyzer-2.0.0.dist-info → birdnet_analyzer-2.0.1.dist-info}/METADATA +137 -129
  117. birdnet_analyzer-2.0.1.dist-info/RECORD +125 -0
  118. {birdnet_analyzer-2.0.0.dist-info → birdnet_analyzer-2.0.1.dist-info}/WHEEL +1 -1
  119. {birdnet_analyzer-2.0.0.dist-info → birdnet_analyzer-2.0.1.dist-info}/licenses/LICENSE +18 -18
  120. birdnet_analyzer-2.0.0.dist-info/RECORD +0 -117
  121. {birdnet_analyzer-2.0.0.dist-info → birdnet_analyzer-2.0.1.dist-info}/entry_points.txt +0 -0
  122. {birdnet_analyzer-2.0.0.dist-info → birdnet_analyzer-2.0.1.dist-info}/top_level.txt +0 -0
@@ -1,68 +1,75 @@
1
- import json
2
- import os
3
-
4
- import birdnet_analyzer.gui.settings as settings
5
-
6
- SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
7
- LANGUAGE_DIR = os.path.join(os.path.dirname(SCRIPT_DIR), "lang")
8
- LANGUAGE_LOOKUP = {}
9
- TARGET_LANGUAGE = settings.FALLBACK_LANGUAGE
10
-
11
-
12
- def load_local_state():
13
- """
14
- Loads the local language settings and populates the LANGUAGE_LOOKUP dictionary with the appropriate translations.
15
- This function performs the following steps:
16
- """
17
- global LANGUAGE_LOOKUP
18
- global TARGET_LANGUAGE
19
-
20
- settings.ensure_settings_file()
21
-
22
- try:
23
- TARGET_LANGUAGE = json.load(open(settings.GUI_SETTINGS_PATH, encoding="utf-8"))["language-id"]
24
- except FileNotFoundError:
25
- print(f"gui-settings.json not found. Using fallback language {settings.FALLBACK_LANGUAGE}.")
26
-
27
- try:
28
- with open(f"{LANGUAGE_DIR}/{TARGET_LANGUAGE}.json", "r", encoding="utf-8") as f:
29
- LANGUAGE_LOOKUP = json.load(f)
30
- except FileNotFoundError:
31
- print(
32
- f"Language file for {TARGET_LANGUAGE} not found in {LANGUAGE_DIR}. Using fallback language {settings.FALLBACK_LANGUAGE}."
33
- )
34
-
35
- if TARGET_LANGUAGE != settings.FALLBACK_LANGUAGE:
36
- with open(f"{LANGUAGE_DIR}/{settings.FALLBACK_LANGUAGE}.json", "r") as f:
37
- fallback: dict = json.load(f)
38
-
39
- for key, value in fallback.items():
40
- if key not in LANGUAGE_LOOKUP:
41
- LANGUAGE_LOOKUP[key] = value
42
-
43
-
44
- def localize(key: str) -> str:
45
- """
46
- Translates a given key into its corresponding localized string.
47
-
48
- Args:
49
- key (str): The key to be localized.
50
-
51
- Returns:
52
- str: The localized string corresponding to the given key. If the key is not found in the localization lookup, the original key is returned.
53
- """
54
- return LANGUAGE_LOOKUP.get(key, key)
55
-
56
-
57
- def set_language(language: str):
58
- """
59
- Sets the language for the application by updating the GUI settings file.
60
- This function ensures that the settings file exists, reads the current settings,
61
- updates the "language-id" field with the provided language, and writes the updated
62
- settings back to the file.
63
-
64
- Args:
65
- language (str): The language identifier to set in the settings file.
66
- """
67
- if language:
68
- settings.set_setting("language-id", language)
1
+ # ruff: noqa: PLW0603
2
+ import json
3
+ import os
4
+
5
+ from birdnet_analyzer.gui import settings
6
+
7
+ SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
8
+ LANGUAGE_DIR = os.path.join(os.path.dirname(SCRIPT_DIR), "lang")
9
+ LANGUAGE_LOOKUP = {}
10
+ TARGET_LANGUAGE = settings.FALLBACK_LANGUAGE
11
+
12
+
13
+ def load_local_state():
14
+ """
15
+ Loads the local language settings and populates the LANGUAGE_LOOKUP dictionary with the appropriate translations.
16
+ This function performs the following steps:
17
+ """
18
+ global LANGUAGE_LOOKUP
19
+ global TARGET_LANGUAGE
20
+
21
+ settings.ensure_settings_file()
22
+
23
+ try:
24
+ with open(settings.GUI_SETTINGS_PATH, encoding="utf-8") as f:
25
+ settings_data = json.load(f)
26
+
27
+ if "language-id" in settings_data:
28
+ TARGET_LANGUAGE = settings_data["language-id"]
29
+ except FileNotFoundError:
30
+ print(f"gui-settings.json not found. Using fallback language {settings.FALLBACK_LANGUAGE}.")
31
+
32
+ try:
33
+ with open(f"{LANGUAGE_DIR}/{TARGET_LANGUAGE}.json", encoding="utf-8") as f:
34
+ LANGUAGE_LOOKUP = json.load(f)
35
+ except FileNotFoundError:
36
+ print(
37
+ f"Language file for {TARGET_LANGUAGE} not found in {LANGUAGE_DIR}."
38
+ + "Using fallback language {settings.FALLBACK_LANGUAGE}."
39
+ )
40
+
41
+ if TARGET_LANGUAGE != settings.FALLBACK_LANGUAGE:
42
+ with open(f"{LANGUAGE_DIR}/{settings.FALLBACK_LANGUAGE}.json") as f:
43
+ fallback: dict = json.load(f)
44
+
45
+ for key, value in fallback.items():
46
+ if key not in LANGUAGE_LOOKUP:
47
+ LANGUAGE_LOOKUP[key] = value
48
+
49
+
50
+ def localize(key: str) -> str:
51
+ """
52
+ Translates a given key into its corresponding localized string.
53
+
54
+ Args:
55
+ key (str): The key to be localized.
56
+
57
+ Returns:
58
+ str: The localized string corresponding to the given key.
59
+ If the key is not found in the localization lookup, the original key is returned.
60
+ """
61
+ return LANGUAGE_LOOKUP.get(key, key)
62
+
63
+
64
+ def set_language(language: str):
65
+ """
66
+ Sets the language for the application by updating the GUI settings file.
67
+ This function ensures that the settings file exists, reads the current settings,
68
+ updates the "language-id" field with the provided language, and writes the updated
69
+ settings back to the file.
70
+
71
+ Args:
72
+ language (str): The language identifier to set in the settings file.
73
+ """
74
+ if language:
75
+ settings.set_setting("language-id", language)
@@ -1,246 +1,245 @@
1
- import gradio as gr
2
-
3
- import birdnet_analyzer.config as cfg
4
- import birdnet_analyzer.gui.utils as gu
5
- import birdnet_analyzer.gui.localization as loc
6
-
7
- OUTPUT_TYPE_MAP = {
8
- "Raven selection table": "table",
9
- "Audacity": "audacity",
10
- "CSV": "csv",
11
- "Kaleidoscope": "kaleidoscope",
12
- }
13
-
14
-
15
- @gu.gui_runtime_error_handler
16
- def run_batch_analysis(
17
- output_path,
18
- use_top_n,
19
- top_n,
20
- confidence,
21
- sensitivity,
22
- overlap,
23
- merge_consecutive,
24
- audio_speed,
25
- fmin,
26
- fmax,
27
- species_list_choice,
28
- species_list_file,
29
- lat,
30
- lon,
31
- week,
32
- use_yearlong,
33
- sf_thresh,
34
- custom_classifier_file,
35
- output_type,
36
- combine_tables,
37
- locale,
38
- batch_size,
39
- threads,
40
- input_dir,
41
- skip_existing,
42
- progress=gr.Progress(),
43
- ):
44
- from birdnet_analyzer.gui.analysis import run_analysis
45
-
46
- gu.validate(input_dir, loc.localize("validation-no-directory-selected"))
47
- batch_size = int(batch_size)
48
- threads = int(threads)
49
-
50
- if species_list_choice == gu._CUSTOM_SPECIES:
51
- gu.validate(species_list_file, loc.localize("validation-no-species-list-selected"))
52
-
53
- if fmin is None or fmax is None or fmin < cfg.SIG_FMIN or fmax > cfg.SIG_FMAX or fmin > fmax:
54
- raise gr.Error(f"{loc.localize('validation-no-valid-frequency')} [{cfg.SIG_FMIN}, {cfg.SIG_FMAX}]")
55
-
56
- return run_analysis(
57
- None,
58
- output_path,
59
- use_top_n,
60
- top_n,
61
- confidence,
62
- sensitivity,
63
- overlap,
64
- merge_consecutive,
65
- audio_speed,
66
- fmin,
67
- fmax,
68
- species_list_choice,
69
- species_list_file,
70
- lat,
71
- lon,
72
- week,
73
- use_yearlong,
74
- sf_thresh,
75
- custom_classifier_file,
76
- output_type,
77
- combine_tables,
78
- "en" if not locale else locale,
79
- batch_size if batch_size and batch_size > 0 else 1,
80
- threads if threads and threads > 0 else 4,
81
- input_dir,
82
- skip_existing,
83
- True,
84
- progress,
85
- )
86
-
87
-
88
- def build_multi_analysis_tab():
89
- with gr.Tab(loc.localize("multi-tab-title")):
90
- input_directory_state = gr.State()
91
- output_directory_predict_state = gr.State()
92
-
93
- with gr.Row():
94
- with gr.Column():
95
- select_directory_btn = gr.Button(loc.localize("multi-tab-input-selection-button-label"))
96
- directory_input = gr.Matrix(
97
- interactive=False,
98
- headers=[
99
- loc.localize("multi-tab-samples-dataframe-column-subpath-header"),
100
- loc.localize("multi-tab-samples-dataframe-column-duration-header"),
101
- ],
102
- )
103
-
104
- def select_directory_on_empty(): # Nishant - Function modified for For Folder selection
105
- folder = gu.select_folder(state_key="batch-analysis-data-dir")
106
-
107
- if folder:
108
- files_and_durations = gu.get_audio_files_and_durations(folder)
109
- if len(files_and_durations) > 100:
110
- return [folder, files_and_durations[:100] + [["..."]]] # hopefully fixes issue#272
111
- return [folder, files_and_durations]
112
-
113
- return ["", [[loc.localize("multi-tab-samples-dataframe-no-files-found")]]]
114
-
115
- select_directory_btn.click(
116
- select_directory_on_empty, outputs=[input_directory_state, directory_input], show_progress=True
117
- )
118
-
119
- with gr.Column():
120
- select_out_directory_btn = gr.Button(loc.localize("multi-tab-output-selection-button-label"))
121
- selected_out_textbox = gr.Textbox(
122
- label=loc.localize("multi-tab-output-textbox-label"),
123
- interactive=False,
124
- placeholder=loc.localize("multi-tab-output-textbox-placeholder"),
125
- )
126
-
127
- def select_directory_wrapper(): # Nishant - Function modified for For Folder selection
128
- folder = gu.select_folder(state_key="batch-analysis-output-dir")
129
- return (folder, folder) if folder else ("", "")
130
-
131
- select_out_directory_btn.click(
132
- select_directory_wrapper,
133
- outputs=[output_directory_predict_state, selected_out_textbox],
134
- show_progress=False,
135
- )
136
-
137
- (
138
- use_top_n,
139
- top_n_input,
140
- confidence_slider,
141
- sensitivity_slider,
142
- overlap_slider,
143
- merge_consecutive_slider,
144
- audio_speed_slider,
145
- fmin_number,
146
- fmax_number,
147
- ) = gu.sample_sliders()
148
-
149
- (
150
- species_list_radio,
151
- species_file_input,
152
- lat_number,
153
- lon_number,
154
- week_number,
155
- sf_thresh_number,
156
- yearlong_checkbox,
157
- selected_classifier_state,
158
- map_plot,
159
- ) = gu.species_lists()
160
-
161
- with gr.Accordion(loc.localize("multi-tab-output-accordion-label"), open=True):
162
- with gr.Group():
163
- output_type_radio = gr.CheckboxGroup(
164
- list(OUTPUT_TYPE_MAP.items()),
165
- value="table",
166
- label=loc.localize("multi-tab-output-radio-label"),
167
- info=loc.localize("multi-tab-output-radio-info"),
168
- )
169
-
170
- with gr.Row():
171
- with gr.Column():
172
- combine_tables_checkbox = gr.Checkbox(
173
- False,
174
- label=loc.localize("multi-tab-output-combine-tables-checkbox-label"),
175
- info=loc.localize("multi-tab-output-combine-tables-checkbox-info"),
176
- )
177
-
178
- with gr.Row():
179
- skip_existing_checkbox = gr.Checkbox(
180
- False,
181
- label=loc.localize("multi-tab-skip-existing-checkbox-label"),
182
- info=loc.localize("multi-tab-skip-existing-checkbox-info"),
183
- )
184
-
185
- with gr.Row():
186
- batch_size_number = gr.Number(
187
- precision=1,
188
- label=loc.localize("multi-tab-batchsize-number-label"),
189
- value=1,
190
- info=loc.localize("multi-tab-batchsize-number-info"),
191
- minimum=1,
192
- )
193
- threads_number = gr.Number(
194
- precision=1,
195
- label=loc.localize("multi-tab-threads-number-label"),
196
- value=4,
197
- info=loc.localize("multi-tab-threads-number-info"),
198
- minimum=1,
199
- )
200
-
201
- locale_radio = gu.locale()
202
-
203
- start_batch_analysis_btn = gr.Button(loc.localize("analyze-start-button-label"), variant="huggingface")
204
-
205
- result_grid = gr.Matrix(
206
- headers=[
207
- loc.localize("multi-tab-result-dataframe-column-file-header"),
208
- loc.localize("multi-tab-result-dataframe-column-execution-header"),
209
- ],
210
- )
211
-
212
- inputs = [
213
- output_directory_predict_state,
214
- use_top_n,
215
- top_n_input,
216
- confidence_slider,
217
- sensitivity_slider,
218
- overlap_slider,
219
- merge_consecutive_slider,
220
- audio_speed_slider,
221
- fmin_number,
222
- fmax_number,
223
- species_list_radio,
224
- species_file_input,
225
- lat_number,
226
- lon_number,
227
- week_number,
228
- yearlong_checkbox,
229
- sf_thresh_number,
230
- selected_classifier_state,
231
- output_type_radio,
232
- combine_tables_checkbox,
233
- locale_radio,
234
- batch_size_number,
235
- threads_number,
236
- input_directory_state,
237
- skip_existing_checkbox,
238
- ]
239
-
240
- start_batch_analysis_btn.click(run_batch_analysis, inputs=inputs, outputs=result_grid)
241
-
242
- return lat_number, lon_number, map_plot
243
-
244
-
245
- if __name__ == "__main__":
246
- gu.open_window(build_multi_analysis_tab)
1
+ # ruff: noqa: I001
2
+ import gradio as gr
3
+
4
+ import birdnet_analyzer.config as cfg
5
+ import birdnet_analyzer.gui.utils as gu
6
+ import birdnet_analyzer.gui.localization as loc
7
+
8
+ OUTPUT_TYPE_MAP = {
9
+ "Raven selection table": "table",
10
+ "Audacity": "audacity",
11
+ "CSV": "csv",
12
+ "Kaleidoscope": "kaleidoscope",
13
+ }
14
+
15
+
16
+ @gu.gui_runtime_error_handler
17
+ def run_batch_analysis(
18
+ output_path,
19
+ use_top_n,
20
+ top_n,
21
+ confidence,
22
+ sensitivity,
23
+ overlap,
24
+ merge_consecutive,
25
+ audio_speed,
26
+ fmin,
27
+ fmax,
28
+ species_list_choice,
29
+ species_list_file,
30
+ lat,
31
+ lon,
32
+ week,
33
+ use_yearlong,
34
+ sf_thresh,
35
+ custom_classifier_file,
36
+ output_type,
37
+ combine_tables,
38
+ locale,
39
+ batch_size,
40
+ threads,
41
+ input_dir,
42
+ skip_existing,
43
+ progress=gr.Progress(),
44
+ ):
45
+ from birdnet_analyzer.gui.analysis import run_analysis
46
+
47
+ gu.validate(input_dir, loc.localize("validation-no-directory-selected"))
48
+ batch_size = int(batch_size)
49
+ threads = int(threads)
50
+
51
+ if species_list_choice == gu._CUSTOM_SPECIES:
52
+ gu.validate(species_list_file, loc.localize("validation-no-species-list-selected"))
53
+
54
+ if fmin is None or fmax is None or fmin < cfg.SIG_FMIN or fmax > cfg.SIG_FMAX or fmin > fmax:
55
+ raise gr.Error(f"{loc.localize('validation-no-valid-frequency')} [{cfg.SIG_FMIN}, {cfg.SIG_FMAX}]")
56
+
57
+ return run_analysis(
58
+ None,
59
+ output_path,
60
+ use_top_n,
61
+ top_n,
62
+ confidence,
63
+ sensitivity,
64
+ overlap,
65
+ merge_consecutive,
66
+ audio_speed,
67
+ fmin,
68
+ fmax,
69
+ species_list_choice,
70
+ species_list_file,
71
+ lat,
72
+ lon,
73
+ week,
74
+ use_yearlong,
75
+ sf_thresh,
76
+ custom_classifier_file,
77
+ output_type,
78
+ combine_tables,
79
+ locale if locale else "en",
80
+ batch_size if batch_size and batch_size > 0 else 1,
81
+ threads if threads and threads > 0 else 4,
82
+ input_dir,
83
+ skip_existing,
84
+ True,
85
+ progress,
86
+ )
87
+
88
+
89
+ def build_multi_analysis_tab():
90
+ with gr.Tab(loc.localize("multi-tab-title")):
91
+ input_directory_state = gr.State()
92
+ output_directory_predict_state = gr.State()
93
+
94
+ with gr.Row():
95
+ with gr.Column():
96
+ select_directory_btn = gr.Button(loc.localize("multi-tab-input-selection-button-label"))
97
+ directory_input = gr.Matrix(
98
+ interactive=False,
99
+ headers=[
100
+ loc.localize("multi-tab-samples-dataframe-column-subpath-header"),
101
+ loc.localize("multi-tab-samples-dataframe-column-duration-header"),
102
+ ],
103
+ )
104
+
105
+ def select_directory_on_empty(): # Nishant - Function modified for For Folder selection
106
+ folder = gu.select_folder(state_key="batch-analysis-data-dir")
107
+
108
+ if folder:
109
+ files_and_durations = gu.get_audio_files_and_durations(folder)
110
+ if len(files_and_durations) > 100:
111
+ return [folder, files_and_durations[:100] + [["..."]]] # hopefully fixes issue#272
112
+ return [folder, files_and_durations]
113
+
114
+ return ["", [[loc.localize("multi-tab-samples-dataframe-no-files-found")]]]
115
+
116
+ select_directory_btn.click(
117
+ select_directory_on_empty, outputs=[input_directory_state, directory_input], show_progress=True
118
+ )
119
+
120
+ with gr.Column():
121
+ select_out_directory_btn = gr.Button(loc.localize("multi-tab-output-selection-button-label"))
122
+ selected_out_textbox = gr.Textbox(
123
+ label=loc.localize("multi-tab-output-textbox-label"),
124
+ interactive=False,
125
+ placeholder=loc.localize("multi-tab-output-textbox-placeholder"),
126
+ )
127
+
128
+ def select_directory_wrapper(): # Nishant - Function modified for For Folder selection
129
+ folder = gu.select_folder(state_key="batch-analysis-output-dir")
130
+ return (folder, folder) if folder else ("", "")
131
+
132
+ select_out_directory_btn.click(
133
+ select_directory_wrapper,
134
+ outputs=[output_directory_predict_state, selected_out_textbox],
135
+ show_progress=False,
136
+ )
137
+
138
+ (
139
+ use_top_n,
140
+ top_n_input,
141
+ confidence_slider,
142
+ sensitivity_slider,
143
+ overlap_slider,
144
+ merge_consecutive_slider,
145
+ audio_speed_slider,
146
+ fmin_number,
147
+ fmax_number,
148
+ ) = gu.sample_sliders()
149
+
150
+ (
151
+ species_list_radio,
152
+ species_file_input,
153
+ lat_number,
154
+ lon_number,
155
+ week_number,
156
+ sf_thresh_number,
157
+ yearlong_checkbox,
158
+ selected_classifier_state,
159
+ map_plot,
160
+ ) = gu.species_lists()
161
+
162
+ with gr.Accordion(loc.localize("multi-tab-output-accordion-label"), open=True), gr.Group():
163
+ output_type_radio = gr.CheckboxGroup(
164
+ list(OUTPUT_TYPE_MAP.items()),
165
+ value="table",
166
+ label=loc.localize("multi-tab-output-radio-label"),
167
+ info=loc.localize("multi-tab-output-radio-info"),
168
+ )
169
+
170
+ with gr.Row():
171
+ combine_tables_checkbox = gr.Checkbox(
172
+ False,
173
+ label=loc.localize("multi-tab-output-combine-tables-checkbox-label"),
174
+ info=loc.localize("multi-tab-output-combine-tables-checkbox-info"),
175
+ )
176
+
177
+ with gr.Row():
178
+ skip_existing_checkbox = gr.Checkbox(
179
+ False,
180
+ label=loc.localize("multi-tab-skip-existing-checkbox-label"),
181
+ info=loc.localize("multi-tab-skip-existing-checkbox-info"),
182
+ )
183
+
184
+ with gr.Row():
185
+ batch_size_number = gr.Number(
186
+ precision=1,
187
+ label=loc.localize("multi-tab-batchsize-number-label"),
188
+ value=1,
189
+ info=loc.localize("multi-tab-batchsize-number-info"),
190
+ minimum=1,
191
+ )
192
+ threads_number = gr.Number(
193
+ precision=1,
194
+ label=loc.localize("multi-tab-threads-number-label"),
195
+ value=4,
196
+ info=loc.localize("multi-tab-threads-number-info"),
197
+ minimum=1,
198
+ )
199
+
200
+ locale_radio = gu.locale()
201
+
202
+ start_batch_analysis_btn = gr.Button(loc.localize("analyze-start-button-label"), variant="huggingface")
203
+
204
+ result_grid = gr.Matrix(
205
+ headers=[
206
+ loc.localize("multi-tab-result-dataframe-column-file-header"),
207
+ loc.localize("multi-tab-result-dataframe-column-execution-header"),
208
+ ],
209
+ )
210
+
211
+ inputs = [
212
+ output_directory_predict_state,
213
+ use_top_n,
214
+ top_n_input,
215
+ confidence_slider,
216
+ sensitivity_slider,
217
+ overlap_slider,
218
+ merge_consecutive_slider,
219
+ audio_speed_slider,
220
+ fmin_number,
221
+ fmax_number,
222
+ species_list_radio,
223
+ species_file_input,
224
+ lat_number,
225
+ lon_number,
226
+ week_number,
227
+ yearlong_checkbox,
228
+ sf_thresh_number,
229
+ selected_classifier_state,
230
+ output_type_radio,
231
+ combine_tables_checkbox,
232
+ locale_radio,
233
+ batch_size_number,
234
+ threads_number,
235
+ input_directory_state,
236
+ skip_existing_checkbox,
237
+ ]
238
+
239
+ start_batch_analysis_btn.click(run_batch_analysis, inputs=inputs, outputs=result_grid)
240
+
241
+ return lat_number, lon_number, map_plot
242
+
243
+
244
+ if __name__ == "__main__":
245
+ gu.open_window(build_multi_analysis_tab)