From 0e1f5526554cedf95129a681efc6d6b5130bafb7 Mon Sep 17 00:00:00 2001 From: Josef Haupt Date: Mon, 26 Feb 2024 16:06:25 +0100 Subject: [PATCH] Added version check in GUI (#268) * Added version check in GUI * Rename JS function --------- Co-authored-by: Josef Haupt --- gui.py | 63 ++++++++++++++++++++++++++++++----------------------- gui/gui.css | 25 +++++++++++++++++++++ gui/gui.js | 38 ++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 27 deletions(-) create mode 100644 gui/gui.css create mode 100644 gui/gui.js diff --git a/gui.py b/gui.py index 569c8ac0..9e4e0732 100644 --- a/gui.py +++ b/gui.py @@ -7,7 +7,6 @@ sys.stderr = sys.stdout = open("logs.txt", "w") import multiprocessing -from multiprocessing import freeze_support from pathlib import Path import gradio as gr @@ -20,7 +19,6 @@ import species import utils from train import trainModel -import webbrowser _WINDOW: webview.Window OUTPUT_TYPE_MAP = { @@ -364,7 +362,7 @@ def runAnalysis( # Combine results? if not cfg.OUTPUT_FILE is None: - print("Combining results into {}...".format(cfg.OUTPUT_FILE), end='', flush=True) + print(f"Combining results into {cfg.OUTPUT_FILE}...", end="", flush=True) analyze.combineResults(cfg.OUTPUT_PATH, cfg.OUTPUT_FILE) print("done!", flush=True) @@ -434,8 +432,8 @@ def select_subdirectories(): labels = [] for folder in subdirs: - labels_in_folder = folder.split(',') - + labels_in_folder = folder.split(",") + for label in labels_in_folder: if not label in labels: labels.append(label) @@ -455,6 +453,7 @@ def select_file(filetypes=()): The selected file or None of the dialog was canceled. """ files = _WINDOW.create_file_dialog(webview.OPEN_DIALOG, file_types=filetypes) + return files[0] if files else None @@ -472,7 +471,7 @@ def format_seconds(secs: float): hours, secs = divmod(secs, 3600) minutes, secs = divmod(secs, 60) - return "{:2.0f}:{:02.0f}:{:06.3f}".format(hours, minutes, secs) + return f"{hours:2.0f}:{minutes:02.0f}:{secs:06.3f}" def select_directory(collect_files=True): @@ -585,7 +584,7 @@ def start_training( cfg.TRAIN_CACHE_MODE = cache_mode cfg.TRAIN_CACHE_FILE = os.path.join(cache_file, cache_file_name) if cache_mode == "save" else cache_file cfg.TFLITE_THREADS = 1 - cfg.CPU_THREADS = max(1, multiprocessing.cpu_count() - 1) # let's use everything we have (well, almost) + cfg.CPU_THREADS = max(1, multiprocessing.cpu_count() - 1) # let's use everything we have (well, almost) cfg.AUTOTUNE = autotune cfg.AUTOTUNE_TRIALS = autotune_trials @@ -593,7 +592,9 @@ def start_training( def dataLoadProgression(num_files, num_total_files, label): if progress is not None: - progress((num_files, num_total_files), total=num_total_files, unit="files", desc=f"Loading data for '{label}'") + progress( + (num_files, num_total_files), total=num_total_files, unit="files", desc=f"Loading data for '{label}'" + ) def epochProgression(epoch, logs=None): if progress is not None: @@ -606,7 +607,9 @@ def trialProgression(trial): if progress is not None: progress((trial, autotune_trials), total=autotune_trials, unit="trials", desc=f"Autotune in progress") - history = trainModel(on_epoch_end=epochProgression, on_trial_result=trialProgression, on_data_load_end=dataLoadProgression) + history = trainModel( + on_epoch_end=epochProgression, on_trial_result=trialProgression, on_data_load_end=dataLoadProgression + ) if len(history.epoch) < epochs: gr.Info("Stopped early - validation metric not improving.") @@ -845,37 +848,36 @@ def on_custom_classifier_selection_click(): if __name__ == "__main__": - freeze_support() + multiprocessing.freeze_support() def build_header(): # Custom HTML header with gr.Markdown + # There has to be another way, but this works for now; paths are weird in gradio with gr.Row(): gr.Markdown( - """ + f"""
- +

BirdNET Analyzer

- """.format( - utils.img2base64("gui/img/birdnet_logo.png") # There has to be another way, but this works for now; paths are weird in gradio - ) + """ ) def build_footer(): with gr.Row(): gr.Markdown( - """ + f"""
-
GUI version: {}
Model version: {}
+
+
GUI version: {cfg.GUI_VERSION}
+
Model version: {cfg.MODEL_VERSION}
+
K. Lisa Yang Center for Conservation Bioacoustics
Chemnitz University of Technology
For docs and support visit:
birdnet.cornell.edu/analyzer
- """.format( - cfg.GUI_VERSION, cfg.MODEL_VERSION - ) - ) - + """ + ) def build_single_analysis_tab(): with gr.Tab("Single file"): @@ -1007,16 +1009,22 @@ def on_output_type_change(value, check): return gr.Checkbox(visible=value == "Raven selection table"), gr.Textbox(visible=check) output_type_radio.change( - on_output_type_change, inputs=[output_type_radio, combine_tables_checkbox], outputs=[combine_tables_checkbox, output_filename], show_progress=False + on_output_type_change, + inputs=[output_type_radio, combine_tables_checkbox], + outputs=[combine_tables_checkbox, output_filename], + show_progress=False, ) def on_combine_tables_change(value): return gr.Textbox(visible=value) combine_tables_checkbox.change( - on_combine_tables_change, inputs=combine_tables_checkbox, outputs=output_filename, show_progress=False + on_combine_tables_change, + inputs=combine_tables_checkbox, + outputs=output_filename, + show_progress=False, ) - + with gr.Row(): batch_size_number = gr.Number( precision=1, label="Batch size", value=1, info="Number of samples to process at the same time." @@ -1155,7 +1163,7 @@ def on_autotune_change(value): autotune_cb.change( on_autotune_change, inputs=autotune_cb, outputs=[custom_params, autotune_params], show_progress=False - ) + ) with gr.Row(): @@ -1404,7 +1412,8 @@ def select_directory_and_update_tb(): ) with gr.Blocks( - css=r".d-block .wrap {display: block !important;} .mh-200 {max-height: 300px; overflow-y: auto !important;} footer {display: none !important;} #single_file_audio, #single_file_audio * {max-height: 81.6px; min-height: 0;}", + css="gui/gui.css", + js="gui/gui.js", theme=gr.themes.Default(), analytics_enabled=False, ) as demo: diff --git a/gui/gui.css b/gui/gui.css new file mode 100644 index 00000000..75551657 --- /dev/null +++ b/gui/gui.css @@ -0,0 +1,25 @@ +.d-block .wrap { + display: block !important; +} + +.mh-200 { + max-height: 300px; + overflow-y: auto !important; +} + +footer { + display: none !important; +} + +#single_file_audio, +#single_file_audio * { + max-height: 81.6px; + min-height: 0; +} + +#update-notification { + background: green; + border-radius: 50%; + width: 1rem; + height: 1rem; +} \ No newline at end of file diff --git a/gui/gui.js b/gui/gui.js new file mode 100644 index 00000000..e952d831 --- /dev/null +++ b/gui/gui.js @@ -0,0 +1,38 @@ +function checkForNewerVersion() { + function sendGetRequest(url) { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + xhr.open("GET", url); + xhr.onload = () => { + if (xhr.status === 200) { + resolve(xhr.responseText); + } else { + reject(new Error(`Request failed with status ${xhr.status}`)); + } + }; + xhr.onerror = () => { + reject(new Error("Request failed")); + }; + xhr.send(); + }); + } + + const apiUrl = "https://api.github.com/repos/kahst/BirdNET-Analyzer/releases/latest"; + + sendGetRequest(apiUrl) + .then(response => { + const current_version = "v" + document.getElementById("current-version").textContent; + const response_object = JSON.parse(response); + const latest_version = response_object.tag_name; + + if (current_version !== latest_version) { + const updateNotification = document.getElementById("update-available"); + + updateNotification.style.display = "block"; + updateNotification.getElementsByTagName("a")[0].href = response_object.html_url; + } + }) + .catch(error => { + console.error(error); + }); +} \ No newline at end of file