From 7946d2a6168a812e292fe11237d618c0c6bb7e68 Mon Sep 17 00:00:00 2001 From: Josef Haupt Date: Tue, 20 Aug 2024 15:37:00 +0200 Subject: [PATCH 1/2] save last directory selection --- .gitignore | 3 ++- gui.py | 68 ++++++++++++++++++++++++++++++++++--------------- localization.py | 25 +++++++++++++++++- 3 files changed, 74 insertions(+), 22 deletions(-) diff --git a/.gitignore b/.gitignore index f74e890a..c4b4312e 100644 --- a/.gitignore +++ b/.gitignore @@ -161,4 +161,5 @@ train_data/ train_cache.npz autotune/ -gui-settings.json \ No newline at end of file +gui-settings.json +state.json \ No newline at end of file diff --git a/gui.py b/gui.py index 3e50dccf..8306525c 100644 --- a/gui.py +++ b/gui.py @@ -43,7 +43,7 @@ from train import trainModel import localization as loc -loc.load_localization() +loc.load_local_state() SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__)) @@ -389,7 +389,9 @@ def runAnalysis( analyze.combineResults([i[1] for i in result_list]) print("done!", flush=True) - return [[os.path.relpath(r[0], input_dir), bool(r[1])] for r in result_list] if input_dir else result_list[0][1]["csv"] + return ( + [[os.path.relpath(r[0], input_dir), bool(r[1])] for r in result_list] if input_dir else result_list[0][1]["csv"] + ) _CUSTOM_SPECIES = loc.localize("species-list-radio-option-custom-list") @@ -442,15 +444,20 @@ def show_species_choice(choice: str): ] -def select_subdirectories(): +def select_subdirectories(state_key=None): """Creates a directory selection dialog. Returns: A tuples of (directory, list of subdirectories) or (None, None) if the dialog was canceled. """ - dir_name = _WINDOW.create_file_dialog(webview.FOLDER_DIALOG) + + initial_dir = loc.get_state(state_key, "") if state_key else "" + dir_name = _WINDOW.create_file_dialog(webview.FOLDER_DIALOG, directory=initial_dir) if dir_name: + if state_key: + loc.set_state(state_key, dir_name[0]) + subdirs = utils.list_subdirectories(dir_name[0]) labels = [] @@ -466,7 +473,7 @@ def select_subdirectories(): return None, None -def select_file(filetypes=()): +def select_file(filetypes=(), state_key=None): """Creates a file selection dialog. Args: @@ -475,9 +482,16 @@ def select_file(filetypes=()): Returns: The selected file or None of the dialog was canceled. """ - files = _WINDOW.create_file_dialog(webview.OPEN_DIALOG, file_types=filetypes) + initial_selection = loc.get_state(state_key, "") if state_key else "" + files = _WINDOW.create_file_dialog(webview.OPEN_DIALOG, file_types=filetypes, directory=initial_selection) + + if files: + if state_key: + loc.set_state(state_key, files[0]) - return files[0] if files else None + return files[0] + + return None def format_seconds(secs: float): @@ -497,7 +511,7 @@ def format_seconds(secs: float): return f"{hours:2.0f}:{minutes:02.0f}:{secs:06.3f}" -def select_directory(collect_files=True, max_files=None): +def select_directory(collect_files=True, max_files=None, state_key=None): """Shows a directory selection system dialog. Uses the pywebview to create a system dialog. @@ -510,7 +524,11 @@ def select_directory(collect_files=True, max_files=None): else just the directory path. All values will be None of the dialog is cancelled. """ - dir_name = _WINDOW.create_file_dialog(webview.FOLDER_DIALOG) + initial_dir = loc.get_state(state_key, "") if state_key else "" + dir_name = _WINDOW.create_file_dialog(webview.FOLDER_DIALOG, directory=initial_dir) + + if dir_name and state_key: + loc.set_state(state_key, dir_name[0]) if collect_files: if not dir_name: @@ -881,14 +899,14 @@ def species_lists(opened=True): selected_classifier_state = gr.State() def on_custom_classifier_selection_click(): - file = select_file(("TFLite classifier (*.tflite)",)) + file = select_file(("TFLite classifier (*.tflite)",), state_key="custom_classifier_file") if file: labels = os.path.splitext(file)[0] + "_Labels.txt" return file, gr.File(value=[file, labels], visible=True) - return None + return None, None classifier_selection_button.click( on_custom_classifier_selection_click, @@ -1027,7 +1045,7 @@ def build_multi_analysis_tab(): ) def select_directory_on_empty(): - res = select_directory(max_files=101) + res = select_directory(max_files=101, state_key="batch-analysis-data-dir") if res[1]: if len(res[1]) > 100: @@ -1050,7 +1068,7 @@ def select_directory_on_empty(): ) def select_directory_wrapper(): - return (select_directory(collect_files=False),) * 2 + return (select_directory(collect_files=False, state_key="batch-analysis-output-dir"),) * 2 select_out_directory_btn.click( select_directory_wrapper, @@ -1162,7 +1180,9 @@ def build_train_tab(): elem_classes="matrix-mh-200", ) select_directory_btn.click( - select_subdirectories, outputs=[input_directory_state, directory_input], show_progress=False + partial(select_subdirectories, state_key="train-data-dir"), + outputs=[input_directory_state, directory_input], + show_progress=False, ) with gr.Column(): @@ -1183,9 +1203,11 @@ def build_train_tab(): ) def select_directory_and_update_tb(): - dir_name = _WINDOW.create_file_dialog(webview.FOLDER_DIALOG) + initial_dir = loc.get_state("train-output-dir", "") + dir_name = _WINDOW.create_file_dialog(webview.FOLDER_DIALOG, directory=initial_dir) if dir_name: + loc.set_state("train-output-dir", dir_name[0]) return ( dir_name[0], gr.Textbox(label=dir_name[0] + "\\", visible=True), @@ -1361,9 +1383,11 @@ def on_crop_select(new_crop_mode): ) def select_directory_and_update(): - dir_name = _WINDOW.create_file_dialog(webview.FOLDER_DIALOG) + initial_dir = loc.get_state("train-data-cache-file-output", "") + dir_name = _WINDOW.create_file_dialog(webview.FOLDER_DIALOG, directory=initial_dir) if dir_name: + loc.set_state("train-data-cache-file-output", dir_name[0]) return ( dir_name[0], gr.Textbox(label=dir_name[0] + "\\", visible=True), @@ -1382,7 +1406,7 @@ def select_directory_and_update(): cache_file_input = gr.File(file_types=[".npz"], visible=False, interactive=False) def on_cache_file_selection_click(): - file = select_file(("NPZ file (*.npz)",)) + file = select_file(("NPZ file (*.npz)",), state_key="train_data_cache_file") if file: return file, gr.File(value=file, visible=True) @@ -1442,7 +1466,7 @@ def build_segments_tab(): output_directory_state = gr.State() def select_directory_to_state_and_tb(): - return (select_directory(collect_files=False),) * 2 + return (select_directory(collect_files=False, state_key="segments-data-dir"),) * 2 with gr.Row(): select_audio_directory_btn = gr.Button( @@ -1738,9 +1762,11 @@ def select_subdir(new_value: str, next_review_state: dict): return {review_state: next_review_state} def start_review(next_review_state): - dir_name = _WINDOW.create_file_dialog(webview.FOLDER_DIALOG) + initial_dir = loc.get_state("review-input-dir", "") + dir_name = _WINDOW.create_file_dialog(webview.FOLDER_DIALOG, directory=initial_dir) if dir_name: + loc.set_state("review-input-dir", dir_name[0]) next_review_state["input_directory"] = dir_name[0] specieslist = [e.name for e in os.scandir(next_review_state["input_directory"]) if e.is_dir()] @@ -1870,9 +1896,11 @@ def build_species_tab(): ) def select_directory_and_update_tb(name_tb): - dir_name = _WINDOW.create_file_dialog(webview.FOLDER_DIALOG) + initial_dir = loc.get_state("species-output-dir", "") + dir_name = _WINDOW.create_file_dialog(webview.FOLDER_DIALOG, directory=initial_dir) if dir_name: + loc.set_state("species-output-dir", dir_name[0]) return ( dir_name[0], gr.Textbox(label=dir_name[0] + "\\", visible=True, value=name_tb), diff --git a/localization.py b/localization.py index 7e1789d2..587f00b4 100644 --- a/localization.py +++ b/localization.py @@ -7,6 +7,7 @@ LANGUAGE_LOOKUP = {} TARGET_LANGUAGE = FALLBACK_LANGUAGE GUI_SETTINGS_PATH = os.path.join(SCRIPT_DIR, "gui-settings.json") +STATE_SETTINGS_PATH = os.path.join(SCRIPT_DIR, "state.json") def ensure_settings_file(): @@ -16,7 +17,29 @@ def ensure_settings_file(): f.write(json.dumps(settings, indent=4)) -def load_localization(): +def get_state_dict() -> dict: + + try: + with open(STATE_SETTINGS_PATH, "r", encoding="utf-8") as f: + return json.load(f) + except FileNotFoundError: + with open(STATE_SETTINGS_PATH, "w") as f: + json.dump({}, f) + return {} + + +def get_state(key: str, default=None) -> str: + return get_state_dict().get(key, default) + + +def set_state(key: str, value: str): + state = get_state_dict() + state[key] = value + with open(STATE_SETTINGS_PATH, "w") as f: + json.dump(state, f, indent=4) + + +def load_local_state(): global LANGUAGE_LOOKUP global TARGET_LANGUAGE From 344a5705cdcb751eecf505cfcca1b275b28bb36a Mon Sep 17 00:00:00 2001 From: Max Mauermann Date: Mon, 26 Aug 2024 11:34:43 +0200 Subject: [PATCH 2/2] folders in segments tab each have their own statekey now --- gui.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gui.py b/gui.py index 8306525c..ebd4659b 100644 --- a/gui.py +++ b/gui.py @@ -1465,8 +1465,8 @@ def build_segments_tab(): result_directory_state = gr.State() output_directory_state = gr.State() - def select_directory_to_state_and_tb(): - return (select_directory(collect_files=False, state_key="segments-data-dir"),) * 2 + def select_directory_to_state_and_tb(state_key): + return (select_directory(collect_files=False, state_key=state_key),) * 2 with gr.Row(): select_audio_directory_btn = gr.Button( @@ -1474,7 +1474,7 @@ def select_directory_to_state_and_tb(): ) selected_audio_directory_tb = gr.Textbox(show_label=False, interactive=False) select_audio_directory_btn.click( - select_directory_to_state_and_tb, + partial(select_directory_to_state_and_tb, state_key="segments-audio-dir"), outputs=[selected_audio_directory_tb, audio_directory_state], show_progress=False, ) @@ -1489,7 +1489,7 @@ def select_directory_to_state_and_tb(): placeholder=loc.localize("segments-tab-results-input-textbox-placeholder"), ) select_result_directory_btn.click( - select_directory_to_state_and_tb, + partial(select_directory_to_state_and_tb, state_key="segments-result-dir"), outputs=[result_directory_state, selected_result_directory_tb], show_progress=False, ) @@ -1502,7 +1502,7 @@ def select_directory_to_state_and_tb(): placeholder=loc.localize("segments-tab-output-selection-textbox-placeholder"), ) select_output_directory_btn.click( - select_directory_to_state_and_tb, + partial(select_directory_to_state_and_tb, state_key="segments-output-dir"), outputs=[selected_output_directory_tb, output_directory_state], show_progress=False, )