diff --git a/SG/__pycache__/demo_pandas_table.cpython-39.pyc b/SG/__pycache__/demo_pandas_table.cpython-39.pyc index 949ba13276e467ff7fe6d6001c553f5d07beb757..17df63900c6661853e8d8d56ad746d1098c0daf7 100644 Binary files a/SG/__pycache__/demo_pandas_table.cpython-39.pyc and b/SG/__pycache__/demo_pandas_table.cpython-39.pyc differ diff --git a/SG/__pycache__/fviewer.cpython-39.pyc b/SG/__pycache__/fviewer.cpython-39.pyc index bad44caf477d2a750681070a8cbe566bce957441..7a18c04fd1d94d39de1f8fec12598bcd4801ade5 100644 Binary files a/SG/__pycache__/fviewer.cpython-39.pyc and b/SG/__pycache__/fviewer.cpython-39.pyc differ diff --git a/SG/__pycache__/multilanguage.cpython-39.pyc b/SG/__pycache__/multilanguage.cpython-39.pyc index 82ed0adf557fb773f4bb3e0cbb656ac1ae485914..450f61c15d10dce42331d3fa358d7b7ab05fa4b0 100644 Binary files a/SG/__pycache__/multilanguage.cpython-39.pyc and b/SG/__pycache__/multilanguage.cpython-39.pyc differ diff --git a/SG/__pycache__/table_show.cpython-39.pyc b/SG/__pycache__/table_show.cpython-39.pyc index f1c5413c1c72f272171ede90a92403589958ddc5..15a93ca84910b5e68f61dde6ddb439162688e74f 100644 Binary files a/SG/__pycache__/table_show.cpython-39.pyc and b/SG/__pycache__/table_show.cpython-39.pyc differ diff --git a/SG/ccser_gui.py b/SG/ccser_gui.py index 747eab2b65ffdd89ebb1aad8ec2f742ef42f00d8..6a630099a414935bd7febf0f684cc121a480e345 100644 --- a/SG/ccser_gui.py +++ b/SG/ccser_gui.py @@ -1,7 +1,11 @@ ## +from multilanguage import get_language_translator + +lang = get_language_translator("English") +lang = get_language_translator("Chinese") + import inspect import os - import constants.beauty as bt import constants.uiconfig as ufg import data_visualization as dv @@ -14,20 +18,21 @@ from constants.beauty import ( ccser_theme, db_introduction, h2, - logo, option_frame, result_frame, ) +import constants.logo as logo + +logo = logo.ASCII_Art_logo from constants.uiconfig import ML_KEY, __version__ from demo_programs.Demo_Nice_Buttons import image_file_to_bytes, red_pill64, wcolor from fviewer import audio_viewer_layout, fviewer_events, selected_files from joblib import load -from multilanguage import get_your_language_translator from user import UserAuthenticatorGUI from config.algoparams import ava_cv_modes -lang = get_your_language_translator("English") + import sys # from psgdemos import * @@ -67,7 +72,7 @@ algorithm = "" audio_selected = "" speech_folder = speech_dbs_dir start_train_key = "start train" -no_result_yet = f"No Result Yet" + predict_res_key = "emotion_predict_res" std_scaler_key = "std_scaler" pca_key = "pca_params" @@ -88,13 +93,16 @@ current_model_key = "current_model" current_model_tip_key = "current_model_tip" predict_proba_tips_key = "predict_proba" cv_splits_slider_key = "cv_splits_slider" - +language_switch_key = "language_switch" +set_theme_key="set theme" train_cv_result_table_key = "train_cv_result_table" # test_score&train_score view train_result_table_key = "train_result_table" predict_proba_table_key = "predict_proba_table" predict_proba_frame_key = "predict_proba_frame" predict_proba_table_frame_key = "predict_proba_table_frame" +browsw_file_with_history = "broswe file with history" +language_select_key = "language_select" userUI = UserAuthenticatorGUI() # ---辅助信息--- @@ -130,7 +138,7 @@ def get_train_fit_start_layout(): [ # sg.Button('start train'), sg.RButton( - "start train", + lang.start_train, image_data=image_file_to_bytes(red_pill64, (100, 50)), button_color=("white", "white"), # button_color=wcolor, @@ -138,7 +146,11 @@ def get_train_fit_start_layout(): pad=(0, 0), key="start train", ), - sg.pin(sg.T("current model:", key=current_model_tip_key, visible=False)), + sg.pin( + sg.T( + lang.current_model_prompt, key=current_model_tip_key, visible=False + ) + ), sg.T("", key=current_model_key), ] ] @@ -152,7 +164,10 @@ def make_window(theme=None, size=None): if theme: # print(theme) sg.theme(theme) - menu_def = [["&Application", ["E&xit"]], ["Help", ["Introduction"]]] + menu_def = [ + [lang.application_menu, [lang.exit_menu]], + [lang.help_menu, [lang.introduction_menu]], + ] # ---user register and login--- user_layout = get_user_layout() # ---choose theme--- @@ -172,7 +187,7 @@ def make_window(theme=None, size=None): train_result_frame_layout = train_res_frame_layout(train_result_tables_layout) confution_matrix_button_layout = [ - [sg.B("show confusion matrix", key=show_confusion_matrix_key)], + [sg.B(lang.show_confusion_matrix, key=show_confusion_matrix_key)], ] file_choose_layout = get_file_choose_layout() @@ -212,9 +227,7 @@ def make_window(theme=None, size=None): # output tab analyzer_layout = get_analyzer_layout() - settings_layout = [ - [sg.Text("Settings")], - ] + theme_layout + settings_layout = get_settings_layout() about_layout = info_layout # ---column right--- right_column_layout = audio_viewer_layout @@ -256,11 +269,11 @@ def make_window(theme=None, size=None): sg.TabGroup( [ [ - sg.Tab("WelcomeUser", user_layout), - sg.Tab("MainPage", main_tab_layout), - sg.Tab("Analyzer", analyzer_layout), - sg.Tab("Settings", settings_layout), - sg.Tab("about", about_layout), + sg.Tab(lang.welcome, user_layout), + sg.Tab(lang.main_page, main_tab_layout), + sg.Tab(lang.analyzer, analyzer_layout), + sg.Tab(lang.settings, settings_layout), + sg.Tab(lang.about, about_layout), ] ], key="-TAB GROUP-", @@ -283,6 +296,25 @@ def make_window(theme=None, size=None): return window +def get_settings_layout(): + theme_layout = get_theme_layout() + + language_frame = [ + [ + sg.Listbox( + values=["English", "中文"], + key=language_select_key, + enable_events=True, + size=bt.lb_narrow_size, + ), + ], + [sg.Button(lang.language_switch, key=language_switch_key)], + ] + settings_layout = [[sg.Text(lang.settings)], *theme_layout, *language_frame] + + return settings_layout + + def get_user_layout(): global userUI userUI = UserAuthenticatorGUI() @@ -299,7 +331,7 @@ def train_res_frame_layout(train_result_tables_layout): train_result_frame_layout = [ [ bt.result_frame( - title=lang["train_result_title"], + title=lang.train_result_title, layout=train_result_tables_layout, frame_key="train_result_frame", ), @@ -311,9 +343,9 @@ def train_res_frame_layout(train_result_tables_layout): def get_db_choose_layout(): db_choose_layout = [ - [bt.h2("Select the training database")], + [bt.h2(lang.select_training_db)], [sg.Combo(ava_dbs, key="train_db", default_value=emodb, enable_events=True)], - [bt.h2("Select the testing database")], + [bt.h2(lang.select_testing_db)], [sg.Combo(ava_dbs, key="test_db", default_value=emodb, enable_events=True)], ] @@ -322,20 +354,16 @@ def get_db_choose_layout(): def get_theme_layout(): theme_layout = [ - [ - sg.Text( - "See how elements look under different themes by choosing a different theme here!" - ) - ], + [sg.Text(lang.theme_prompt)], [ sg.Listbox( values=sg.theme_list(), - size=bt.lb_size, + size=bt.lb_narrow_size, key="-THEME LISTBOX-", enable_events=True, ) ], - [sg.Button("Set Theme")], + [sg.Button(lang.set_theme,key=set_theme_key)], ] return theme_layout @@ -343,7 +371,7 @@ def get_theme_layout(): def get_file_choose_layout(): file_choose_layout = [ - [bt.h2(lang["choose_audio"])], + [bt.h2(lang.choose_audio)], [ sg.Combo( sorted(sg.user_settings_get_entry("-filenames-", [])), @@ -351,18 +379,20 @@ def get_file_choose_layout(): size=(50, 1), key="-FILENAME-", ), - sg.FileBrowse(), - sg.B("Clear History"), + sg.FileBrowse( + button_text=lang.file_browse, key=browsw_file_with_history + ), # target参数可用 + sg.B(lang.clear_history), ], [ - sg.Button("OK", bind_return_key=True, key="file_choose_ok"), + sg.Button(lang.OK, bind_return_key=True, key="file_choose_ok"), # sg.Button("Cancel"), # ], # [ sg.B( - "Recognize it", + lang.recognize_it, key="recognize it", - tooltip=lang["recognize_the_audio_emotion"], + tooltip=lang.recognize_the_audio_emotion, ), ], ] @@ -375,7 +405,7 @@ def get_train_res_tables_layout(): [ sg.Table( values=[["pending"] * 2], - headings=["train_score", "test_score"], + headings=[lang.train_score, lang.test_score], justification="center", font="Arial 16", expand_x=True, @@ -387,7 +417,7 @@ def get_train_res_tables_layout(): [ sg.Table( values=[["pending"] * 2], - headings=["fold", "accu_score"], + headings=[lang.fold_field, lang.accu_score_field], justification="center", font="Arial 16", expand_x=True, @@ -407,7 +437,7 @@ def get_title_layout(): [ sg.Text( # "Welcome to experience CCSER Client!", - lang["welcome_title"], + lang.welcome_title, size=bt.welcom_title_size, justification="center", font=("Comic", 50), @@ -421,16 +451,22 @@ def get_title_layout(): def get_draw_layout(): + WaveForm = lang.WaveForm + FreqGraph = lang.FreqGraph + MelFreqGraph = lang.MelFreqGraph draw_layout = [ - [bt.h2(lang["draw_diagram"], tooltip=lang["draw_diagram_detail"])], + [bt.h2(lang.draw_diagram, tooltip=lang.draw_diagram_detail)], # [sg.Input(), sg.FileBrowse()], [ - sg.Checkbox("waveForm", key="wave_form"), - sg.Checkbox("FreqGraph", key="freq_graph"), - sg.Checkbox("MelFreqGraph", key="mel_freq_graph"), + sg.Checkbox(WaveForm, key="wave_form", default=False), + sg.Checkbox(FreqGraph, key="freq_graph", default=False), + sg.Checkbox(MelFreqGraph, key="mel_freq_graph", default=False), ], # todo reset - [sg.Button("draw_graph"), sg.Button("Reset", key="reset graph Checkbox")], + [ + sg.Button(lang.draw_diagram, key="draw diagram"), + sg.Button("Reset", key="reset graph Checkbox"), + ], ] return draw_layout @@ -483,22 +519,22 @@ def get_logging_viewer_layout(): def get_analyzer_layout(): analyzer_log_printer_layout = [ - [bt.h2("Anything printed will display here!")], - [ - sg.Multiline( - size=bt.ml_size, - # expand_x=True, - # expand_y=True, - write_only=True, - reroute_stdout=True, - reroute_stderr=True, - echo_stdout_stderr=True, - autoscroll=True, - auto_refresh=True, - ) - ], - ] - + [bt.h2("Anything printed will display here!")], + [ + sg.Multiline( + size=bt.ml_size, + # expand_x=True, + # expand_y=True, + write_only=True, + reroute_stdout=True, + reroute_stderr=True, + echo_stdout_stderr=True, + autoscroll=True, + auto_refresh=True, + ) + ], + ] + # analyzer_layout = ( # analyzer_log_printer # + dv.layout @@ -541,7 +577,7 @@ def get_info_layout(): def get_predict_res_layout(): predict_res_layout = bt.res_content_layout( - text=no_result_yet, justification="c", key=predict_res_key + text=lang.no_result_yet, justification="c", key=predict_res_key ) # 默认不显示predict_proba的不可用说明 @@ -553,7 +589,7 @@ def get_predict_res_layout(): [ sg.Table( values=[["pending"] * 2], - headings=["emotino", "proba"], + headings=[lang.emotion_field, lang.proba_field], justification="c", font="Arial 16", expand_x=True, @@ -567,22 +603,15 @@ def get_predict_res_layout(): ] predict_prob_layout = [*predict_proba_tips_layout, *predict_proba_table_layout] predict_res_frames_layout = [ - [result_frame(layout=predict_res_layout)], + [result_frame(title=lang.result_frame_prompt, layout=predict_res_layout)], [ result_frame( - title="predict_proba_tips", + title=lang.predict_proba_legend, layout=predict_prob_layout, frame_key=predict_proba_frame_key, # visible=False, ) ], - # [ - # result_frame( - # title="predict_proba_table", - # layout=predict_proba_table_layout, - # frame_key=predict_proba_table_frame_key, - # ), - # ], ] return predict_res_frames_layout @@ -639,7 +668,7 @@ def get_other_settings_layout(): other_settings_frame_layout = [ [ bt.option_frame( - title="Other Parameter Settings", layout=cv_param_settings_layout + title=lang.other_parameter_legend, layout=cv_param_settings_layout ), ], ] @@ -652,7 +681,7 @@ def get_algo_layout(): len_of_algos = len(algos) algo_frame = option_frame( - title="Algorithms chooser", + title=lang.algorithmes_chooser_title, layout=[ algos[: len_of_algos // 2], algos[len_of_algos // 2 :], @@ -660,7 +689,7 @@ def get_algo_layout(): frame_key="algo_border_frame", ) algos_layout = [ - [bt.h2(lang["choose_algorithm"])], + [bt.h2(lang.choose_algorithm)], [algo_frame], ] @@ -682,16 +711,16 @@ def get_e_config_layout(): e_config_layout = [ [ bt.h2( - text="choose the emotion config", + text=lang.choose_emotion_config_title, # relief=sg.RELIEF_SOLID, # style_add='underline', style_add="italic", - tooltip=lang["choose_emotion_config"], + tooltip=lang.choose_emotion_config, ), ], [ bt.option_frame( - title="Emotion Config chooser", layout=emotion_config_checboxes_layout + title=lang.emotion_config_legend, layout=emotion_config_checboxes_layout ) ], ] @@ -699,11 +728,9 @@ def get_e_config_layout(): return e_config_layout - - def get_f_config_layout(): f_config_option_frame = option_frame( - title="Feature Config chooser", + title=lang.feature_config_legend, layout=[ [ sg.Checkbox("MFCC", key="mfcc", default=True, enable_events=True), @@ -716,7 +743,7 @@ def get_f_config_layout(): frame_key="f_config_layout", ) f_config_layout = [ - [bt.h2(lang["choose_feature_config"])], + [bt.h2(lang.choose_feature_config)], [f_config_option_frame], ] @@ -725,7 +752,7 @@ def get_f_config_layout(): def get_f_transform_layout(): f_transform_frame_layout = option_frame( - title="Feature Transform chooser", + title=lang.feature_transform_legend, layout=[ [ sg.Checkbox( @@ -739,23 +766,23 @@ def get_f_transform_layout(): ), ], [ - sg.T('n_components:',tooltip="input the number of components to keep."), + sg.T(lang.n_components_prompt, tooltip=lang.n_components_tooltip), sg.Input( key=pca_components_key, default_text="None", - tooltip=bt.pca_components_tooltip, + tooltip=lang.pca_components_tooltip, enable_events=True, ), sg.Combo( values=ava_svd_solver, default_value="auto", - tooltip=bt.pca_svd_solver_tooltip, + tooltip=lang.pca_svd_solver_tooltip, enable_events=True, key=pca_svd_solver_key, ), ], [ - sg.Text(text="feature_dimension:"), + sg.Text(text=lang.demension_prompt), sg.pin(sg.Text("pending", key=feature_dimension_key)), ], [ @@ -766,12 +793,14 @@ def get_f_transform_layout(): visible=False, ) ), - sg.Text("pending", key=feature_dimension_pca_key, visible=False), + sg.Text( + lang.pending_prompt, key=feature_dimension_pca_key, visible=False + ), ], ], ) f_transform_layout = [ - [bt.h2(lang["feature_transform_config"])], + [bt.h2(lang.feature_transform_config)], [f_transform_frame_layout], ] return f_transform_layout @@ -1000,6 +1029,7 @@ def start_train_model( # model_res(er,verbose=verbose) return er + def fts_params_process(values, verbose): pca_enable = values[pca_enable_key] pca_params = None @@ -1015,8 +1045,10 @@ def fts_params_process(values, verbose): if verbose: print(fts, "@{fts}🎈") - fts_res = {key: value for key, value in fts.items() if value is not None and value != False} - print(fts_res,"@{fts_res}") + fts_res = { + key: value for key, value in fts.items() if value is not None and value != False + } + print(fts_res, "@{fts_res}") return fts_res @@ -1043,6 +1075,9 @@ def model_res(er, verbose=1): ## def main(verbose=1): + # lang=lang + global theme + global lang theme = ccser_theme window = make_window(theme=theme, size=size) # Initialize the selected databases list @@ -1141,32 +1176,50 @@ def main(verbose=1): audio_selected=audio_selected, ) - elif event == "draw_graph": + elif event == "draw diagram": wave_form = values["wave_form"] freq_graph = values["freq_graph"] mel_freq_graph = values["mel_freq_graph"] - # print(f"{event=}in draw tasks..(开始绘制.)") - if wave_form: - showWaveForm(audio_selected) - if freq_graph: - showFreqGraph(audio_selected) - if mel_freq_graph: - showMelFreqGraph(audio_selected) + if verbose: + print(f"{event=}in draw tasks..(开始绘制.)") + print( + f"tasks:", + f"{[wave_form,freq_graph,mel_freq_graph]},@{[wave_form,freq_graph,mel_freq_graph]}", + ) + if audio_selected: + if wave_form: + showWaveForm(audio_selected) + if freq_graph: + showFreqGraph(audio_selected) + if mel_freq_graph: + showMelFreqGraph(audio_selected) + else: + sg.popup(f"{audio_selected}" + lang.not_exist) # print("完成图形绘制.") - elif event == "Set Theme": + elif event == set_theme_key: # print("[LOG] Clicked Set Theme!") select_items_list = values["-THEME LISTBOX-"] theme_chosen = values["-THEME LISTBOX-"][0] if verbose: print(select_items_list, "@{select_item}") print("[LOG] User Chose Theme: " + str(theme_chosen)) + #TODO why the call of window.close cause the GUI broken? window.close() print("the window was closed!") # window = make_window(theme=theme_chosen) # if(window): # print("restart successful!") # window = make_window() + elif event == language_select_key: + language = values[language_select_key][0] + lang=get_language_translator(language=language) + if verbose: + print("language: ", language) + print('lang: ', lang) + + window.Refresh() + elif event == "Introduction": content = [logo, db_introduction] res = "\n".join(content) @@ -1218,9 +1271,7 @@ def refresh_trained_view(verbose, window, er, values): ae = er.ae window[feature_dimension_key].update(value=ae.feature_dimension) window[feature_dimension_pca_tip_key].update(visible=True) - window[feature_dimension_pca_key].update( - value=ae.get_dimensions(), visible=True - ) + window[feature_dimension_pca_key].update(value=ae.get_dimensions(), visible=True) n_splits = values[cv_splits_slider_key] # cv_mode=values[kfold_radio_key] diff --git a/SG/constants/__pycache__/beauty.cpython-39.pyc b/SG/constants/__pycache__/beauty.cpython-39.pyc index 2628badf15fb436b4bff844205d1f3b75ecdddf5..69ac635f1e357cea46a0a58d36208c55c743cc47 100644 Binary files a/SG/constants/__pycache__/beauty.cpython-39.pyc and b/SG/constants/__pycache__/beauty.cpython-39.pyc differ diff --git a/SG/constants/__pycache__/logo.cpython-39.pyc b/SG/constants/__pycache__/logo.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eabeabc73bbc54924d2fc7105ece6d8ef383d943 Binary files /dev/null and b/SG/constants/__pycache__/logo.cpython-39.pyc differ diff --git a/SG/constants/beauty.py b/SG/constants/beauty.py index a48551c227a5d4102a1aa8e2908bb2a754391d64..31c24b6d29a64c656e093171509266d4a6531932 100644 --- a/SG/constants/beauty.py +++ b/SG/constants/beauty.py @@ -1,15 +1,16 @@ import PySimpleGUI as sg # import constants.uiconfig as ufg -from SG.multilanguage import get_your_language_translator +from SG.multilanguage import get_language_translator,lang -lang = get_your_language_translator("English") import sys frame_size = (600, 50) # frame_size=600#给定一个整形数的时候,仅指定宽度,高度被自动设置为1 # frame_size=None +#listbox_size lb_size = (60, 10) +lb_narrow_size=(20,10) ml_size = (60, 20) seperator_color = "blue" score_ndigits=4 @@ -22,60 +23,9 @@ tips_bgc='lightyellow' result_font = ("Arial", 20, "bold underline") normal_font=("Arial", 10,"italic") -logo = """ -░█████╗░░█████╗░░██████╗███████╗██████╗░░░░░░░░█████╗░██╗░░░░░██╗███████╗███╗░░██╗████████╗𝓫𝔂 𝓬𝔁𝔁𝓾 -██╔══██╗██╔══██╗██╔════╝██╔════╝██╔══██╗░░░░░░██╔══██╗██║░░░░░██║██╔════╝████╗░██║╚══██╔══╝ -██║░░╚═╝██║░░╚═╝╚█████╗░█████╗░░██████╔╝█████╗██║░░╚═╝██║░░░░░██║█████╗░░██╔██╗██║░░░██║░░░ -██║░░██╗██║░░██╗░╚═══██╗██╔══╝░░██╔══██╗╚════╝██║░░██╗██║░░░░░██║██╔══╝░░██║╚████║░░░██║░░░ -╚█████╔╝╚█████╔╝██████╔╝███████╗██║░░██║░░░░░░╚█████╔╝███████╗██║███████╗██║░╚███║░░░██║░░░ -░╚════╝░░╚════╝░╚═════╝░╚══════╝╚═╝░░╚═╝░░░░░░░╚════╝░╚══════╝╚═╝╚══════╝╚═╝░░╚══╝░░░╚═╝░░░ -""" - - -pca_components_tooltip = """ -PCA components -Number of components to keep. if n_components is not set all -components are kept: - -n_components == min(n_samples, n_features) -If n_components == 'mle' and svd_solver == 'full', Minka’s MLE -is used to guess the dimension. Use of n_components == 'mle' will -interpret svd_solver == 'auto' as svd_solver == 'full'. -If 0 < n_components < 1 and svd_solver == 'full', select -the number of components such that the amount of variance that -needs to be explained is greater than the percentage specified -by n_components. -If svd_solver == 'arpack', the number of components must - be strictly less than the minimum of n_features and n_samples. - -Hence, the None case results in: - -n_components == min(n_samples, n_features) - 1 -""" -pca_svd_solver_tooltip = """ -If auto : -The solver is selected by a default policy based on X.shape and -n_components: - if the input data is larger than 500x500 and the number of components - to extract is lower than 80% of the smallest dimension of the data, - then the more efficient ‘randomized’ method is enabled. Otherwise - the exact full SVD is computed and optionally truncated afterwards. - -If full : -run exact full SVD calling the standard LAPACK solver via scipy. -linalg.svd and select the components by postprocessing - -If arpack : -run SVD truncated to n_components calling ARPACK solver via -scipy.sparse.linalg.svds. It requires strictly - 0 < n_components < min(X.shape) - -If randomized : -run randomized SVD by the method of Halko et al. -""" @@ -256,7 +206,7 @@ def option_frame( def result_frame( - title=lang["result_frame"], + title=lang.result_frame_prompt, # result="inputYourContentToHighligt", layout=None, title_color=title_color, diff --git a/SG/constants/logo.py b/SG/constants/logo.py new file mode 100644 index 0000000000000000000000000000000000000000..d59d4fc69969f720ab32caacaafea0f35f1af972 --- /dev/null +++ b/SG/constants/logo.py @@ -0,0 +1,9 @@ +ASCII_Art_logo = """ +░█████╗░░█████╗░░██████╗███████╗██████╗░░░░░░░░█████╗░██╗░░░░░██╗███████╗███╗░░██╗████████╗𝓫𝔂 𝓬𝔁𝔁𝓾 +██╔══██╗██╔══██╗██╔════╝██╔════╝██╔══██╗░░░░░░██╔══██╗██║░░░░░██║██╔════╝████╗░██║╚══██╔══╝ +██║░░╚═╝██║░░╚═╝╚█████╗░█████╗░░██████╔╝█████╗██║░░╚═╝██║░░░░░██║█████╗░░██╔██╗██║░░░██║░░░ +██║░░██╗██║░░██╗░╚═══██╗██╔══╝░░██╔══██╗╚════╝██║░░██╗██║░░░░░██║██╔══╝░░██║╚████║░░░██║░░░ +╚█████╔╝╚█████╔╝██████╔╝███████╗██║░░██║░░░░░░╚█████╔╝███████╗██║███████╗██║░╚███║░░░██║░░░ +░╚════╝░░╚════╝░╚═════╝░╚══════╝╚═╝░░╚═╝░░░░░░░╚════╝░╚══════╝╚═╝╚══════╝╚═╝░░╚══╝░░░╚═╝░░░ + +""" \ No newline at end of file diff --git a/SG/demo_pandas_table.py b/SG/demo_pandas_table.py index ba9d1641d1772bde20281576c5400bcc6534a621..a32a478860b79aa7289345b47ad844466273fb64 100644 --- a/SG/demo_pandas_table.py +++ b/SG/demo_pandas_table.py @@ -37,8 +37,7 @@ class TablePandas(): layout = self.create_table_window(df) window = sg.Window("Pandas Table Viewer", layout) return window - # def show_confution_matrix_window(df): - # window=get_confution_matrix_window(df) + def show_confution_matrix_window(self,df=None): diff --git a/SG/fviewer.py b/SG/fviewer.py index 21abc09cbf68971a6fe47fc01392b7c25f237171..1d17cd1e94a09d2ad90e34e177de67efa3a4e726 100644 --- a/SG/fviewer.py +++ b/SG/fviewer.py @@ -8,19 +8,24 @@ from config.MetaPath import speech_dbs_dir, savee import constants.uiconfig as ufg import table_show as ts import constants.beauty as bt +from SG.multilanguage import get_language_translator # from recognizer.basic import EmotionRecognizer import data_visualization as dv +# from SG.translations import en,zh +language = "en" +lang = get_language_translator(language) + # 主题设置说明:当主题设置语句防止在程序的末尾时可能是无效的 # 猜测sg.theme()设置完主题后,后续在调用sg的元素创建方法才会有相应主题的配色 # 如果控件都已经创建好了才开始调用sg.theme()修改配色,那来不及起作用了 sg.theme(bt.ccser_theme) # 常量 -listbox_default_value_tip = "hover your mouse in this listbox area to check tooltips!" + audio_listbox_values = [ - "click filter or input regex to scan audio file!", - listbox_default_value_tip, + lang.click_filter_prompt, + lang.listbox_default_value_prompt, ] # 将变量设置在事件循环中可能会反复被初始化,这里我们应该放在事件循环的外部 @@ -34,25 +39,11 @@ selected_files = [] # er: EmotionRecognizer = None er = None t: ts.TableShow = None -filter_tooltip = """ - the listbox of files allow you to choose one or more files \n using left button of your mouse, -you can use `Ctrl+Click` to select multiple files(jump to the selected file is allowed too!) - - you can right click after you choose one or more files to do something like these: - 1.file size - 2.file path(absolute path) - 3.recognize emotion - 4.play file(audio) you choosed - *.all of above could work in multiple files one by one automatically -""" -selected_files_tooltip = """ -you can observe the files your choosed in last listBox -Whether it is a continuous selection or a skip selection, -these selected files will be tightly arranged and -the number of files will be displayed at the top -""" -filter_input_key = "filter_input" +selected_files_tooltip = lang.selected_files_tooltip +filter_tooltip = lang.filter_tooltip + +filter_input_key = "filter_input" files_browsed_key = "files browsed" selected_files_listbox_key = "selected_files_list" num_selected_files_key = "num_selected_files" @@ -64,6 +55,8 @@ audio_file_list_key = "audio_files_list" confirm_files_selected_key = "confirm files selected" confirm_folder_selected_key = "confirm folder selected" filter_audios_key = "filter audios" +speech_folder_path_input_key = "speech_folder_path_input" +speech_folder_path_chooser_key = "speech_folder_path_chooser" ## @@ -96,6 +89,15 @@ def get_audios_regex( ) # 调试模式,切片出一小部分来试验算法 # audios=audios[:50] + + # 正则表达式模式 + if filter_regex: + if verbose: + print("filter_regex:> ", filter_regex) + # 由于这里需要反复使用正则匹配,因此采用编译的方式来提高性能 + p = re.compile(filter_regex, re.IGNORECASE) + # s = re.search(filter_regex, str(path), re.IGNORECASE) + filtered_audios = [] for path in audios: # print(path) @@ -106,11 +108,9 @@ def get_audios_regex( else: path = path.absolute() # 对路径进行正则过滤 - #todo 对括号的识别有问题(得益于模块化,可以直接在这个模块内启动图形界面进行调试) + # todo 对括号的识别有问题(得益于模块化,可以直接在这个模块内启动图形界面进行调试) if filter_regex: - if verbose: - print('filter_regex:> ', filter_regex) - s = re.search(filter_regex, str(path), re.IGNORECASE) + s = p.search(str(path)) if s: filtered_audios.append(path) else: @@ -154,8 +154,7 @@ def get_audios(folder, exts, pattern="*", recursive=False, flatten=True, verbose ## # 创建GUI窗口 folder_browse_init_dir = speech_dbs_dir / savee # 作为一个初始值 -speech_folder_path_input_key = "speech_folder_path_input" -speech_folder_path_chooser_key = "speech_folder_path_chooser" + default_folder_file_list = get_audios_regex( recursive=True, speech_folder_root=speech_dbs_dir, short=True ) @@ -166,102 +165,131 @@ len_default_folder_file_list = len(default_folder_file_list) right_click_menu = [ "", - ["Show File Path", "Show File Size", "Play Audio", "Emotion Recognize"], + [lang.show_file_path, lang.show_file_size, lang.play_audio, lang.emotion_recognize], ] -audio_viewer_layout = [ - [sg.Text("Select a directory:")], - [ - sg.InputText( - default_text=speech_folder, - key=speech_folder_path_input_key, - tooltip="you can paste or type a dir path!\n or use the right side Browse button to choose a dir", - ), - sg.FolderBrowse( - initial_folder=folder_browse_init_dir, - button_text="folder browse", - change_submits=True, - key=speech_folder_path_chooser_key, - target=speech_folder_path_input_key, - # enable_events=True, - tooltip=f"choose a folder you want to do SER,\nthe default folder is {speech_folder}", - ), - ], - [sg.B(confirm_folder_selected_key)], - [ - sg.Input( - default_text="select multiple files,which will be shown here ", - key=files_browsed_key, - ), - # sg.Text(text="files selected by filesBrowse will be shown \n in the listbox below"), - sg.FilesBrowse( - target=files_browsed_key, - key="FilesBrowse", - enable_events=True, - change_submits=True, - ), - sg.OK(key="confirm files selected"), - ], - [ - sg.Text("current directory:"), - sg.Text(f"{speech_folder}", key="current_dir"), - ], - [ - sg.Checkbox( - text="Recursively scan subdirectories", - default=True, - key=recursive_checkbox_key, - enable_events=True, - ), - sg.Checkbox( - text="auto refresh", - default=False, - key=auto_refresh_checkbox_key, - enable_events=True, - ), - sg.Checkbox( - text="short path", default=True, key=short_path_checkbox_key, enable_events=True - ), - ], - [ - sg.Text("Filter by regex:"), - sg.InputText(key="filter_input", default_text="", enable_events=True), - ], - [ - sg.B(filter_audios_key, tooltip="click to manual refresh the files listbox"), - # sg.Button(ufg.close), - ], - [sg.Text(f"{len_default_folder_file_list} files", key="num_files_text")], - [ - sg.Listbox( - values=default_folder_file_list, - # size=(50, 10), - size=bt.lb_size, - key=audio_file_list_key, - enable_events=True, - bind_return_key=True, - tooltip=filter_tooltip, - # 定义位于列表中条目的右键菜单内容 - right_click_menu=right_click_menu, - select_mode=sg.LISTBOX_SELECT_MODE_EXTENDED, - no_scrollbar=True, - ) - ], - [ - sg.Text("Selected audio files:"), - sg.Text(f"0 files", key=num_selected_files_key), - ], - [ - sg.Listbox( - values=audio_listbox_values, - size=bt.lb_size, - key=selected_files_listbox_key, - tooltip=selected_files_tooltip, - right_click_menu=right_click_menu, - select_mode=sg.LISTBOX_SELECT_MODE_EXTENDED, - ) - ], -] + +files_selected_prompt = lang.files_selected_prompt + + +def audio_viewer_layout(theme=""): + if theme: + sg.theme(theme) + audio_viewer_layout = [ + + [sg.Text(lang.select_dir_prompt), + # change the visible to True to try the language and theme switch! + sg.Button("restart", visible=False)], + [ + sg.InputText( + default_text=speech_folder, + key=speech_folder_path_input_key, + tooltip=lang.path_input_tooltip, + ), + sg.FolderBrowse( + initial_folder=folder_browse_init_dir, + button_text=lang.folder_browse, + change_submits=True, + key=speech_folder_path_chooser_key, + target=speech_folder_path_input_key, + # enable_events=True, + tooltip=f"{lang.choose_folder_tooltip}{speech_folder}", + ), + ], + [sg.Button(lang.confirm_folder_selected, key=confirm_folder_selected_key)], + [ + sg.Input( + default_text=files_selected_prompt, + key=files_browsed_key, + ), + # sg.Text(text="files selected by filesBrowse will be shown \n in the listbox below"), + sg.FilesBrowse( + button_text=lang.files_browse, + target=files_browsed_key, + key="FilesBrowse", + enable_events=True, + change_submits=True, + ), + ], + [ + sg.OK( + button_text=lang.confirm_files_selected_button, + key=confirm_files_selected_key, + ), + ], + [ + sg.Text(lang.current_directory_prompt), + sg.Text(f"{speech_folder}", key="current_dir"), + ], + [ + sg.Checkbox( + text=lang.recursively_scan_subdir, + default=True, + key=recursive_checkbox_key, + enable_events=True, + ), + sg.Checkbox( + text=lang.auto_refresh, + default=False, + key=auto_refresh_checkbox_key, + enable_events=True, + ), + sg.Checkbox( + text=lang.short_path, + default=True, + key=short_path_checkbox_key, + enable_events=True, + ), + ], + [ + sg.Text(lang.filter_by_regex_prompt), + sg.InputText(key="filter_input", default_text="", enable_events=True), + ], + [ + sg.Button( + button_text=lang.filter_audios, + key=filter_audios_key, + tooltip=lang.auto_refresh_tooltip, + ), + # sg.Button(ufg.close), + ], + [sg.Text(f"{len_default_folder_file_list} files", key="num_files_text")], + [ + sg.Listbox( + values=default_folder_file_list, + # size=(50, 10), + size=bt.lb_size, + key=audio_file_list_key, + enable_events=True, + bind_return_key=True, + tooltip=filter_tooltip, + # 定义位于列表中条目的右键菜单内容 + right_click_menu=right_click_menu, + select_mode=sg.LISTBOX_SELECT_MODE_EXTENDED, + no_scrollbar=True, + ) + ], + [ + sg.Text(lang.selected_audios_prompt), + sg.Text(lang.no_files, key=num_selected_files_key), + ], + [ + sg.Listbox( + values=audio_listbox_values, + size=bt.lb_size, + key=selected_files_listbox_key, + tooltip=selected_files_tooltip, + right_click_menu=right_click_menu, + select_mode=sg.LISTBOX_SELECT_MODE_EXTENDED, + ) + ], + ] + return audio_viewer_layout + + +def make_window(theme): + window = sg.Window("Audio Viewer", audio_viewer_layout(theme), resizable=True) + return window # 定义文件大小计算函数 @@ -319,14 +347,19 @@ def get_abs_selected_pathes(speech_folder_path, selected_files): def main(): - layout = audio_viewer_layout - - window = sg.Window("Audio File Filter", layout, resizable=True) + layout = audio_viewer_layout() + global lang + window = sg.Window(lang.audios_filter, layout, resizable=True) while True: event, values = window.read() print(event, "@{event} main") if event in (sg.WINDOW_CLOSED, ufg.close): break + elif event == "restart": + window.close() + print("closed successfully!") + lang = get_language_translator("zh") + window = make_window(theme="Reds") else: # 处理事件(小心,如果下面的函数编写不当,可能使得某些控件不能够正常工作) # 例如,FolderBrowser生成的按钮点击无法呼出系统的资源管理器(或者需要反复点击) @@ -355,7 +388,7 @@ def fviewer_events(window, event=None, values=None, verbose=1): # 判断手动输入的路径是否合法 if event == confirm_folder_selected_key: path = values[speech_folder_path_input_key] - print(path, "was confirmed") + print(path, "was confirmed!") if Path(path).exists(): speech_folder = path # 更新当前speech_path控件 @@ -363,7 +396,7 @@ def fviewer_events(window, event=None, values=None, verbose=1): # 更新文件列表视图 refresh_viewer(window, speech_folder=path, values=values) else: - sg.popup_error(f"{path} not exist!") + sg.popup_error(f"{path} {lang.not_exist}") # 刷新文件列表 elif event == filter_input_key and not values[auto_refresh_checkbox_key]: return @@ -387,7 +420,7 @@ def fviewer_events(window, event=None, values=None, verbose=1): refresh_selected_view(window, num_selected_files) # 处理 "Show File Path" 事件 - elif event == "Show File Path": + elif event == lang.show_file_path: res = [] for file in selected_files: res.append(get_absolute_path(speech_folder, file)) @@ -395,7 +428,7 @@ def fviewer_events(window, event=None, values=None, verbose=1): sg.popup(selected_file_pathes, title="File Path") # 处理 "Show File Size" 事件 - elif event == "Show File Size": + elif event == lang.show_file_size: # selected_file = get_abs_selected_pathes(speech_folder_path, selected_files) res = [] for selected_file in selected_files: @@ -407,7 +440,7 @@ def fviewer_events(window, event=None, values=None, verbose=1): res = "\n".join(res) sg.popup(f"{res}", title="File Size") # 处理 "Play Audio" 事件 - elif event == "Play Audio": + elif event == lang.play_audio: pathes = get_abs_selected_pathes(speech_folder, selected_files) print(pathes, selected_files) @@ -421,7 +454,7 @@ def fviewer_events(window, event=None, values=None, verbose=1): # 播放音频 audio_file = AudioSegment.from_file(audio_path, format=ext) play(audio_file) - elif event == "Emotion Recognize": + elif event == lang.emotion_recognize: # print() # 为了完成多选文件(成批识别),经过brainstorm,提出以下idea: # 委托给ccser_gui模块来处理,通过共享变量来简单通信/创建一个媒介模块来解决相互导入的问题(对于这种简单的场景够用的) @@ -431,7 +464,7 @@ def fviewer_events(window, event=None, values=None, verbose=1): # 这里的识别应该在训练阶段完成之后才调用的,否则程序应该组织这样跨阶段的行为,提高robustness if er == None: print("请先完成识别器训练,然后再执行识别操作") - sg.popup("please train the SER model and then try angin!") + sg.popup(lang.train_model_warning, text_color="red") else: print(f"the emotion recognizer is {er}!") res_content: list[str] = [] @@ -448,7 +481,9 @@ def fviewer_events(window, event=None, values=None, verbose=1): print(emo_res, "@{emo_res}") print(abs_pathes, "@{abs_pathes}") - t = ts.TableShow(header=["emotion", "path"], data_lists=[emo_res, abs_pathes]) + t = ts.TableShow( + header=["emotion", "path"], data_lists=[emo_res, abs_pathes] + ) print(t.lists, "@{t.lists}") t.run() @@ -460,9 +495,7 @@ def fviewer_events(window, event=None, values=None, verbose=1): def refresh_selected_view(window, num_selected_files): # 数量 - window[num_selected_files_key].Update( - f"Selected audio files: ({num_selected_files} files)" - ) + window[num_selected_files_key].Update(f"({num_selected_files}{lang.files_count})") # 内容 window[selected_files_listbox_key].Update(values=selected_files) @@ -479,7 +512,7 @@ def refresh_viewer(window, speech_folder=None, values=None, delay=1, verbose=1): recursive = values[recursive_checkbox_key] short = values[short_path_checkbox_key] filter_regex = values[filter_input_key] - auto_refresh=values[auto_refresh_checkbox_key] + auto_refresh = values[auto_refresh_checkbox_key] # print(short, "@{short}🎈") @@ -496,7 +529,9 @@ def refresh_viewer(window, speech_folder=None, values=None, delay=1, verbose=1): num_files = len(audio_files) # 将扫描到的文件更新到窗口对应组件中,在下一次read方法调用时,画面就会显示新的内容 window[audio_file_list_key].update(values=audio_files) - window[num_files_key].update(f"Filtered audio files: ({num_files} files)") + window[num_files_key].update( + f"{lang.filterd_audios}({num_files} {lang.files_count})" + ) if __name__ == "__main__": diff --git a/SG/multilanguage.py b/SG/multilanguage.py index 875db008bc1b389f4a3ed516e95c56e4781a614f..f433e8fc15b1d885308ea4aa744e208173b7c12b 100644 --- a/SG/multilanguage.py +++ b/SG/multilanguage.py @@ -1,18 +1,35 @@ import PySimpleGUI as sg import json -from config.MetaPath import trans_en,trans_zh +from config.MetaPath import trans_en_json,trans_zh_json +from SG.translations import en,zh +# lang\["(.+)"\] +#lang.$1 +lang=en +English_marks = ('English','英文','en') +Chinese_marks = ('中文',"Chinese",'zh','cn') -def get_your_language_translator(language="English"): - if language in ('English','英文'): - with open(trans_en, 'r',encoding='utf-8') as f: +def get_language_translator(language="English"): + global lang + if language in English_marks: + lang=en + # return en + # return zh + elif language in Chinese_marks: + lang=zh + return lang + +def get_language_translator_json(language="Chinese"): + if language in English_marks: + with open(trans_en_json, 'r',encoding='utf-8') as f: translations = json.load(f) - elif language in ('中文',"Chinese"): + elif language in Chinese_marks: # encoding='utf-8',否则中文字符报错:UnicodeDecodeError: 'charmap' codec can't decode byte 0x81 in position 53: character maps to - with open(trans_zh, 'r',encoding='utf-8') as f: + with open(trans_zh_json, 'r',encoding='utf-8') as f: translations = json.load(f) - return translations + lang=translations + return lang @@ -35,10 +52,11 @@ def run_app(): break elif event == 'OK': # 根据用户的选择读取相应的语言翻译文件 - translations = get_your_language_translator(values) - + translations = get_language_translator(values['language']) + print(translations,values) # 显示欢迎消息 - welcome_message = translations['welcome_message'] + # welcome_message = translations['welcome_message'] + welcome_message = translations.welcome_message window['welcome_message'].update(welcome_message) # 关闭 GUI 窗口 @@ -46,4 +64,7 @@ def run_app(): if __name__ == '__main__': - run_app() \ No newline at end of file + # res=get_your_language_translator('中文') + # print('res: ', res) + run_app() + \ No newline at end of file diff --git a/SG/snippet_cxxu.py b/SG/snippet_cxxu.py index 30466040918b35707671b06e9eccf0f066c53a8c..32668d0fd2aadb4e60bc22129a407050838443b0 100644 --- a/SG/snippet_cxxu.py +++ b/SG/snippet_cxxu.py @@ -1 +1 @@ -recursive \ No newline at end of file +emotion \ No newline at end of file diff --git a/SG/table_show.py b/SG/table_show.py index 4a28db9daa8ac11a5372aa3bb86945e8cd7d4b27..eed109bf5bc2a473afa2a32e860b2a0378409c2c 100644 --- a/SG/table_show.py +++ b/SG/table_show.py @@ -1,6 +1,8 @@ import PySimpleGUI as sg import pandas as pd from config.MetaPath import recognize_result_dir +from SG.multilanguage import get_language_translator,lang + class TableShow(): def __init__(self,header=None,data_lists=None): """将二维列表作为表格数据显示 @@ -22,7 +24,7 @@ class TableShow(): self.data_df=pd.DataFrame(self.data_rows,columns=self.header) # 创建表格布局 - warning="the save operation will comsume some time to complete!Be patient!" + save_patient_warning=lang.save_patient_warning self.layout = [ [ sg.Table( @@ -37,9 +39,9 @@ class TableShow(): expand_y=True, ) ], - [sg.Text("if you want to recognize the next batch files,please close the window first!\n in the future,the client may be support multiple threads to improve the user experience")], - [sg.Text("save result to a csv file")], - [sg.Button(f"save to file",tooltip=f"click to save to a csv file!\n{warning}")], + [sg.Text(lang.close_table_prompt)], + [sg.Text(lang.save_to_csv_prompt)], + [sg.Button(f"save to file",tooltip=f"{save_patient_warning}")], ] def run(self): diff --git a/SG/translations/__pycache__/en.cpython-39.pyc b/SG/translations/__pycache__/en.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..77a621d08ad35f594c7a360327acc8826e2d3286 Binary files /dev/null and b/SG/translations/__pycache__/en.cpython-39.pyc differ diff --git a/SG/translations/__pycache__/zh.cpython-39.pyc b/SG/translations/__pycache__/zh.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c79826504f7e383fbbc6390e4cad2fda47806bf4 Binary files /dev/null and b/SG/translations/__pycache__/zh.cpython-39.pyc differ diff --git a/SG/translations/c2e.py b/SG/translations/c2e.py new file mode 100644 index 0000000000000000000000000000000000000000..a3589d809f69ac5a749ebef5befb5dbf03bec9e8 --- /dev/null +++ b/SG/translations/c2e.py @@ -0,0 +1,25 @@ +## +import re +p=re.compile(r'\s*(.*)(\s*=.*)') +from config.MetaPath import trans_en,trans_zh,project_dir,translations_dir + +res=[] +with open(trans_en,'r',encoding='utf-8')as fe: + with open(trans_zh,'r',encoding='utf-8')as fz: + i=1 + for e,z in zip(fe,fz): + # print(e,z) + # print(i) + # i+=1 + if e.strip() and z.strip(): + varName=p.search(e).group(1) + # print('varName: ', varName) + value=p.search(z).group(2) + line=f'{varName}{value}' + # print(line) + res.append(line) + else:res.append(z.strip()) +with open(trans_zh,'w',encoding='utf-8') as fout: + for line in res: + fout.write(line+'\n') + print(line) \ No newline at end of file diff --git a/SG/translations/dict_to_vars.py b/SG/translations/dict_to_vars.py new file mode 100644 index 0000000000000000000000000000000000000000..1e996460fefc7d3ccdc76e35bd9d8f2881f1a51c --- /dev/null +++ b/SG/translations/dict_to_vars.py @@ -0,0 +1,29 @@ +## + +import re +from config.MetaPath import trans_en,trans_zh,project_dir,translations_dir +# p=re.compile(r'"(.*)"(=".*")') +text = '"result_training": "result of model training:",' + +p = re.compile(r'\s*"(.+?)"(.*?:)(.*".+"),?') + + +r = "./en.json" +t = "./en.py" + +r="./zh.json" +t="./zh.py" + +r,t=translations_dir/r,translations_dir/t +with open(file=r,mode='r',encoding='utf-8') as fin: + with open(file=t,mode='w',encoding='utf-8') as fout: + for line in fin: + if line.strip() in ['{','}']: + continue + res=p.sub(r"\1 = \3", line,1) + fout.write(res) + print(res) + +# print(res,"@{res}") +# import en +# en.result_frame diff --git a/SG/translations/en.json b/SG/translations/en.json index eef9be7fa5e00d999dfafe9331320c32ea5fdf2e..26d48ccc43d5201eee61901f5d79a05c177274a8 100644 --- a/SG/translations/en.json +++ b/SG/translations/en.json @@ -2,15 +2,15 @@ "welcome_message": "Welcome to My App!", "choose_emotion_config": "Please select an emotional combination for testing: recommended combinations are AS, HNS, AHNS, AHNPS. \nNote that there is a difference between 'surprise' and 'pleasantSurprise' in the SAVEE dataset, \nso the AHNPS combination is not recommended for use on SAVEE.", "choose_feature_config": "Please choose one or more features", - "feature_transform_config":"feature transformer config", + "feature_transform_config": "feature transformer config", "choose_algorithm": "Choose an algorithm for testing", "choose_audio": "Please select an audio sample file to recognize its emotion.", "recognize_the_audio_emotion": "Recognize the emotion of the selected audio file.", - "draw_diagram":"choose one diagram to draw", + "draw_diagram": "choose one diagram to draw", "draw_diagram_detail": "Draw the [waveform|spectrogram|Mel spectrogram] of the selected file:", "welcome_title": "𝒲ℯ𝓁𝒸ℴ𝓂ℯ 𝓉ℴ ℯ𝓍𝓅ℯ𝓇𝒾ℯ𝓃𝒸ℯ 𝒞𝒞𝒮ℰℛ 𝒞𝓁𝒾ℯ𝓃𝓉!", - "result_training":"result of model training:", - "train_result_title":"Train Result", - "result_frame":"Emotion Of Select File(Predict Result)", - "recognize_it":"Recognize it" + "result_training": "result of model training:", + "train_result_title": "Train Result", + "result_frame": "Emotion Of Select File(Predict Result)", + "recognize_it": "Recognize it" } \ No newline at end of file diff --git a/SG/translations/en.py b/SG/translations/en.py new file mode 100644 index 0000000000000000000000000000000000000000..ad24c939cd65bf27aac20010753c8729f91d0c27 --- /dev/null +++ b/SG/translations/en.py @@ -0,0 +1,153 @@ +welcome_message = "Welcome to My App!" +choose_emotion_config = "Please select an emotional combination for testing: recommended combinations are AS, HNS, AHNS, AHNPS. \nNote that there is a difference between 'surprise' and 'pleasantSurprise' in the SAVEE dataset, \nso the AHNPS combination is not recommended for use on SAVEE." +choose_feature_config = "Please choose one or more features" +feature_transform_config = "feature transformer config" +choose_algorithm = "Choose an algorithm for testing" +choose_audio = "Please select an audio sample file to recognize its emotion." +recognize_the_audio_emotion = "Recognize the emotion of the selected audio file." +draw_diagram = "choose one diagram to draw" +draw_diagram_detail = "Draw the [waveform|spectrogram|Mel spectrogram] of the selected file:" +welcome_title = "𝒲ℯ𝓁𝒸ℴ𝓂ℯ 𝓉ℴ ℯ𝓍𝓅ℯ𝓇𝒾ℯ𝓃𝒸ℯ 𝒞𝒞𝒮ℰℛ 𝒞𝓁𝒾ℯ𝓃𝓉!" +result_training = "result of model training:" +train_result_title = "Train Result" +result_frame_prompt = "Emotion Of Select File(Predict Result)" +recognize_it = "Recognize it" +WaveForm = "WaveForm" +FreqGraph = "FreqGraph" +MelFreqGraph = "MelFreqGraph" +algorithmes_chooser_title="Algorithms chooser" +choose_emotion_config_title="choose the emotion config" +emotion_config_legend="Emotion Config chooser" +feature_transform_legend="Feature Transform chooser" +feature_config_legend="Feature Config chooser" + +n_components_tooltip="input the number of components to keep." +n_components_prompt='n_components:' +demension_prompt="feature_dimension:" +pending_prompt="pending" + +other_parameter_legend="Other Parameter Settings" +select_training_db="Select the training database" +select_testing_db="Select the testing database" +files_selected_prompt="select multiple files,which will be shown here " +confirm_files_selected_button="confirm files selected" +recursively_scan_subdir="Recursively scan subdirectories" +auto_refresh="auto refresh" +auto_refresh_tooltip="click to manual refresh the files listbox" +short_path="short path" +filter_by_regex_prompt="Filter by regex:" +selected_audios_prompt="Selected audio files:" +no_files=f"0 files" +audios_filter="Audio File Filter" +filterd_audios="Filtered audio files: " +files_count=" files" +train_model_warning="please train the SER model and then try angin!" + +selected_files_tooltip = """ +you can observe the files your choosed in last listBox +Whether it is a continuous selection or a skip selection, +these selected files will be tightly arranged and +the number of files will be displayed at the top +""" +filter_tooltip = """ + the listbox of files allow you to choose one or more files \n using left button of your mouse, +you can use `Ctrl+Click` to select multiple files(jump to the selected file is allowed too!) + + you can right click after you choose one or more files to do something like these: + 1.file size + 2.file path(absolute path) + 3.recognize emotion + 4.play file(audio) you choosed + *.all of above could work in multiple files one by one automatically +""" +not_exist="not exist!" +confirm_folder_selected= "confirm folder selected" +folder_browse="folder browse" +choose_folder_tooltip="choose a folder you want to do SER,\nthe default folder is " +files_browse="browse files" +current_directory_prompt="current directory:" +show_file_path="Show File Path" +show_file_size="Show File Size" +play_audio="Play Audio" +emotion_recognize="Emotion Recognize" +path_input_tooltip="you can paste or type a dir path!\n or use the right side Browse button to choose a dir" +click_filter_prompt="click filter or input regex to scan audio file!" +listbox_default_value_prompt = "hover your mouse in this listbox area to check tooltips!" +filter_audios="filter audios" +select_dir_prompt="Select a directory:" + +save_patient_warning="click to save to a csv file!\nthe save operation will comsume some time to complete!Be patient!" +close_table_prompt="if you want to recognize the next batch files,please close the window first!\n in the future,the client may be support multiple threads to improve the user experience" +save_to_csv_prompt="save result to a csv file" + +emotion_field="emotion" +proba_field="proba" +show_confusion_matrix="show confusion matrix" +welcome="WelcomeUser" +main_page="MainPage" +analyzer="Analyzer" +settings="Settings" +about="about" + +OK="OK" +clear_history="Clear History" +set_theme="Set Theme" +theme_prompt="See how elements look under different themes by choosing a different theme here!" + +train_score="train_score" +test_score="test_score" +start_train="start train" +pca_components_tooltip = """ +PCA components +Number of components to keep. if n_components is not set all +components are kept: + +n_components == min(n_samples, n_features) +If n_components == 'mle' and svd_solver == 'full', Minka’s MLE +is used to guess the dimension. Use of n_components == 'mle' will +interpret svd_solver == 'auto' as svd_solver == 'full'. + +If 0 < n_components < 1 and svd_solver == 'full', select +the number of components such that the amount of variance that +needs to be explained is greater than the percentage specified +by n_components. + +If svd_solver == 'arpack', the number of components must + be strictly less than the minimum of n_features and n_samples. + +Hence, the None case results in: + +n_components == min(n_samples, n_features) - 1 +""" +pca_svd_solver_tooltip = """ +If auto : +The solver is selected by a default policy based on X.shape and +n_components: + if the input data is larger than 500x500 and the number of components + to extract is lower than 80% of the smallest dimension of the data, + then the more efficient ‘randomized’ method is enabled. Otherwise + the exact full SVD is computed and optionally truncated afterwards. + +If full : +run exact full SVD calling the standard LAPACK solver via scipy. +linalg.svd and select the components by postprocessing + +If arpack : +run SVD truncated to n_components calling ARPACK solver via +scipy.sparse.linalg.svds. It requires strictly + 0 < n_components < min(X.shape) + +If randomized : +run randomized SVD by the method of Halko et al. +""" +file_browse="BrosweFile" +fold_field="fold" +accu_score_field="accu_score" +application_menu="&Application" +exit_menu="E&xit" +help_menu="Help" +introduction_menu="Introduction" +predict_proba_legend="predict_proba" +current_model_prompt="current model:" +no_result_yet = f"No Result Yet" +language_switch="Switch" diff --git a/SG/translations/zh.py b/SG/translations/zh.py new file mode 100644 index 0000000000000000000000000000000000000000..529441895184d72cb91e982dc6794f49da179409 --- /dev/null +++ b/SG/translations/zh.py @@ -0,0 +1,142 @@ +import SG.constants.logo as logo + +welcome_message = "欢迎来到我的应用程序!" +choose_emotion_config = """ +请选择一个情感组合进行测试:建议使用AS、HNS、AHNS、AHNPS组合。请注意,在SAVEE数据集中, +“surprise”和“pleasantSurprise”之间存在差异,因此不建议在SAVEE上使用AHNPS组合。 +""" +choose_feature_config = "请选择一个或多个特征" +feature_transform_config = "特征变换器配置" +choose_algorithm = "选择一个算法进行测试" +choose_audio = "请选择一个音频样本文件以识别其情感" +recognize_the_audio_emotion = "识别所选音频文件的情感" +draw_diagram = "选择一个图表进行绘制" +draw_diagram_detail = "绘制所选文件的[波形图|频谱图|Mel频谱图]:" +welcome_title = "𝒲ℯ𝓁𝒸ℴ𝓂ℯ 𝓉ℴ ℯ𝓍𝓅ℯ𝓇𝒾ℯ𝓃𝒸ℯ 𝒞𝒞𝒮ℰℛ 𝒞𝓁𝒾ℯ𝓃𝓉!" +result_training = "模型训练结果:" +train_result_title = "训练结果" +result_frame_prompt = "所选文件的情感(预测结果)" +recognize_it = "开始识别" +WaveForm = "波形图" +FreqGraph = "频谱图" +MelFreqGraph = "Mel频谱图" +algorithmes_chooser_title = "算法选择器" +choose_emotion_config_title = "情感配置选择器" +emotion_config_legend = "选择情感配置" +feature_transform_legend = "特征变换选择器" +feature_config_legend = "特征配置选择器" + +n_components_tooltip = "输入要保留的成分数。" +n_components_prompt = "主成分数:" +demension_prompt = "特征维数:" +pending_prompt = "待处理" + +other_parameter_legend = "其他参数设置" +select_training_db = "选择训练数据库" +select_testing_db = "选择测试数据库" +files_selected_prompt = "已选择的文件:" +confirm_files_selected_button = "确认所选文件" +recursively_scan_subdir = "递归扫描子目录" +auto_refresh = "自动刷新" +auto_refresh_tooltip = "点击手动刷新文件列表框" +short_path = "短路径模式" +filter_by_regex_prompt = "使用正则表达式过滤:" +selected_audios_prompt = "已选择的音频文件:" +no_files = "0 个文件" +audios_filter = "音频文件过滤" +filterd_audios = "过滤后的音频文件:" +files_count = " 个文件" +train_model_warning = "请先训练SER模型,然后再试一次!" + +selected_files_tooltip = """ +您可以观察上一个列表框中选择的文件,无论是连续选择还是跳跃选择,这些选择的文件都将被紧密排列,并在顶部显示文件数量。 +""" +filter_tooltip = """ +文件列表框允许您使用鼠标的左键选择一个或多个文件,您可以使用Ctrl +单击选择多个文件(还可以跳转到所选文件!) + +您可以选择一个或多个文件后右键单击以执行以下操作: +1.文件大小 +2.文件路径(绝对路径) +3.识别情感 +4.播放所选文件(音频) +*.以上所有内容都可以在多个文件中自动一一工作 +""" +not_exist = "不存在!" +confirm_folder_selected = "确认已选择的文件夹" +folder_browse = "浏览文件夹" +choose_folder_tooltip = "选择一个要进行SER的文件夹, 默认文件夹为 " +files_browse = "浏览文件" +current_directory_prompt = "当前目录:" +show_file_path = "显示文件路径" +show_file_size = "显示文件大小" +play_audio = "播放音频" +emotion_recognize = "情感识别" +path_input_tooltip = "您可以粘贴或输入目录路径!或使用右侧的浏览按钮选择目录" +click_filter_prompt = "点击过滤器或输入正则表达式来扫描音频文件!" +listbox_default_value_prompt = "将鼠标悬停在此列表框区域以查看工具提示!" +filter_audios = "过滤音频文件" +select_dir_prompt = "选择语音库目录以浏览语音文件" + +save_patient_warning = "点击保存到CSV文件!保存操作将花费一些时间来完成!请耐心等待!" +close_table_prompt = "如果您想识别下一批文件,请先关闭窗口!在未来,客户端可能支持多线程以提高用户体验" +save_to_csv_prompt = "将结果保存到CSV文件" + +emotion_field = "情感" +proba_field = "概率" +show_confusion_matrix = "显示混淆矩阵" +welcome = "欢迎" +main_page = "主页" +analyzer = "分析器" +settings = "设置" +about = "关于" + +OK = "确定" +clear_history = "清除历史记录" +set_theme = "设置主题" +theme_prompt = "通过在此处选择不同的主题来查看元素在不同主题下的外观!" + +train_score = "训练集得分" +test_score = "测试集得分" +start_train = "开始训练" +pca_components_tooltip = """ +PCA组件 +要保留的组件数。如果未设置n_components,则保留所有组件: + +n_components == min(n_samples, n_features) +如果n_components == 'mle'且svd_solver =='full',则使用Minka的MLE猜测维数。使用n_components =='mle'将解释为svd_solver =='auto',即svd_solver =='full'。 + +如果0 < n_components < 1且svd_solver =='full',则选择组件数,使需要解释的方差量大于n_components指定的百分比。 + +如果svd_solver =='arpack',则组件数必须严格小于n_features和n_samples的最小值。 + +因此,None情况的结果为: + +n_components == min(n_samples, n_features) - 1 +""" +pca_svd_solver_tooltip = """ +如果自动: +根据X.shape和n_components选择默认策略选择求解器: +如果输入数据大于500x500并且提取的组件数小于数据的最小维度的80%, +则启用更有效的“随机”方法。否则,计算精确的全SVD,然后可选择截断。 + +如果完整: +通过scipy运行准确的完整SVD。linalg.svd并通过后处理选择组件 + +如果arpack: +通过scipy.sparse.linalg.svds调用截断为n_components的SVD ARPACK求解器。它需要 0 < n_components < min(X.shape) + +如果随机: +通过Halko等人的方法运行随机SVD。 +""" +file_browse = "浏览单个文件" + +fold_field = "k-折" +accu_score_field = "准确度" +application_menu = "&应用程序" +exit_menu = "退出(&x)" +help_menu = "帮助" +introduction_menu = "介绍" +predict_proba_legend = "预测概率" +current_model_prompt = "当前模型:" +no_result_yet = "暂无结果" +language_switch="确认切换" \ No newline at end of file diff --git a/assets/image-20230510185320088.png b/assets/image-20230510185320088.png new file mode 100644 index 0000000000000000000000000000000000000000..0ae1733549edad1867925a09150067a034956f9f Binary files /dev/null and b/assets/image-20230510185320088.png differ diff --git a/config/MetaPath.py b/config/MetaPath.py index e858a59fa1fcb76b863d89661df6b9f202f34cd1..b4b990dceccbfec50262596bb4181d02e1b42467 100644 --- a/config/MetaPath.py +++ b/config/MetaPath.py @@ -37,8 +37,10 @@ ravdess_files_glob_old = "data/ravdess/Actor_*" ravdess_files_glob="data/ravdess/Actor_*/*.wav" savee_files_glob = "data/savee/AudioData/*/*.wav" translations_dir=project_dir/"SG/translations" -trans_zh=translations_dir/"zh.json" -trans_en=translations_dir/"en.json" +trans_zh_json=translations_dir/"zh.json" +trans_en_json=translations_dir/"en.json" +trans_zh=translations_dir/"zh.py" +trans_en=translations_dir/"en.py" # print(trans_en.exists()) #计算绝对路径 diff --git a/config/__pycache__/MetaPath.cpython-39.pyc b/config/__pycache__/MetaPath.cpython-39.pyc index 4fb26e0aadb680bc0bf95bdc05a05843a77ca921..a485b1d4ed5eef890db98d849dac753207eb58ce 100644 Binary files a/config/__pycache__/MetaPath.cpython-39.pyc and b/config/__pycache__/MetaPath.cpython-39.pyc differ diff --git a/presentation_ppt.md b/presentation_ppt.md new file mode 100644 index 0000000000000000000000000000000000000000..6bc4764247a867d05a47dd4cab22afae860abba3 --- /dev/null +++ b/presentation_ppt.md @@ -0,0 +1,142 @@ +--- + +marp: true +# header: 'Header content' +footer: '跨库SER系统的设计与实现' +theme: gaia +class: lead + + +--- + +# 跨库语音情感识别系统的设计与实现 + + +![bg contain left:45% 98% 在这里插入图片描述](https://img-blog.csdnimg.cn/be61e759517a4f038c3eb69928e097aa.png) + + +计科1902 徐超信 +指导老师:蒋海华 + +--- + + + +## 内容目录 + +- 背景和意义 +- 开发路径 +- 实现方案 +- 基础情况 + +--- + +## 背景&意义 + +- 语音是人与人之间最重要、便捷的交流方式,不仅包含人类所要传达的语义信息,还包含人们所要表达情感信息,语言种类等各个方面。在20世纪中期,人机交互系统一直停带于语义文本这一类文字信息的理解和表达上,因此,当时所构建的人机交互系统往往只有用户表达出中性语音时才能够有效地识别出用户意图,而对于自然状态下的情感语音理解极为不佳。 +- 可见,制约着人机交互系统发展的重要因素之一在于情感智能的缺失。在此背景下,越来越多的研究者们开始着手于对情感信息的探索。语音情感识别在智能车载系统,情感机器人,医疗,服务业等领域都发挥着重要作用。 + +--- + + +## 开发路径 + + + +![bg contain right:80% 95% 在这里插入图片描述](https://img-blog.csdnimg.cn/b0fca5b946ea4e20acc513c1ed304c50.png) + + +--- + +## 实现方案 + +--- + +### 语料库的选用 + + + +- EMO-DB : 该数据集是由 10 名演员(分别从5个男性和5个女性说话人的表演语音中获得)模拟 7 种情绪产生的 10 个德语语句, 7 种情绪分别是:中性、愤怒、恐惧、喜悦、悲伤、厌恶和厌倦, 数据库共536 个样本, 该数据库已经成为许多研究的基础。 +- SAVEE: 该数据集是一个使用英国英语的多模态情感数据集。 它总共包含了 480 条语音以及 7 种不同的情感: 中性、快乐、悲伤、愤怒、惊讶、恐惧和厌恶。 这些话语由 4 个专业的男性演员产生。 为了保持情感表演的良好质量, 本数据集的所有录音均由 10 位不同的评价者在音频、视觉和视听条件下进行验证这些录音中的脚本选自常规 TIMIT 语料库。 + +--- + +- RAVDESS: 该数据集是情感语音和歌曲的多模态语料。 该数据集是性别均衡的, 由 24 名专门演员组成, 他们以中性的北美(英语)发音产生语音和歌曲样本。 对于情感性言语, 它由平静、欢乐、悲伤、愤怒、恐惧、惊讶、厌恶构成。 对于情感性的歌曲, 它由平静、欢乐、悲伤、愤怒、恐惧、惊讶、厌恶和恐惧组成。 每个表情都是在情感强度的两个层次上产生的, 带有一个附加的中性表情。 最后收集的 7 356 份录音在情感有效性、强度和真实性方面分别被评为 10 次。 对于这些收视率, 雇佣了来自北美的 247 名未经培训的研究对象。 + +--- + +- 拟选用的上述数据库既可以完成多模态的同语言不同库的跨库识别(SAVEE和RAVDESA)实验,也可以完成跨语言跨库的识别实验(EMO-DB和SAVEE或EMO-DB和RAVDESS)。其中RAVDESS虽然是单模态的语料库库,但是由于其广泛的被采用,可以用来检验SER的基本识别性能,以及和已有的实验进行对比 + +--- + +### 语音特征的提取 + +- + + +--- + +### 分类模型的构建 + + + +![ Schematic diagram of automatic encoder; ](https://img-blog.csdnimg.cn/457d8e29cd074d6a90126238ce5fd73e.png) + +本系统拟采用栈式堆叠稀疏自编码器与核函数极限学习机结合的复合网络模型(SSAE-KELM)作为识别模型。 +Stack Sparse Automatic Encoders - Kernel Extreme Learning Machine + + + +复合网络SSAE-KELM 的结构图解 +![bg contain right:70% ](https://img-blog.csdnimg.cn/63f31dd95c74414dbde9804b71b73811.png) + +--- + +![image-20230112193055545](D:\repos\blogs\graduationDesign\assets\image-20230112193055545.png) + +识别的流程 +![ 在这里插入图片描述](https://img-blog.csdnimg.cn/17fd1086b50043b2aaab511b6a675151.png) + +--- + +基于复合网络 SSAE-KELM 语音情感识别的详细步骤如下: + +1) 多层稀疏自编码器堆叠构成栈式稀疏自编码网络,初始化 SSAE 网络参数; +2) 选择情感语音库,按照大致 2:1 的比例将其分为训练集与测试集,并提取语音情感全局特征 GF; +3) 从上到下无监督逐层贪婪训练每一层 SAE,实现局部最优; +4) 结合标签通过 BP 算法微调整体网络参数,达到全局最优; +5) 提取经过SSAE 无监督预训练有监督微调后的深度特征用于训练KELM 分类器,得到相应的KELM 参数; +6) 保存训练好的网络参数,利用测试集对语音情感识别性能进行测试。 + +--- + +### 小结 + +- 本系统采用一种复合网络栈式稀疏自编码网络——核函数极限学习机,首先通过栈式稀疏自编码网络对原始特征进行无监督预训练。 +- 然后结合数据标签利用反向传播算法有监督微调,重构得到更符合大脑稀疏性且更具有区分情感信息的深度特征。 +- 最后采用人工蜂群优化算法优化的核函数极限学习机对情感进行识别分类。 + +--- + +### 语音情感识别系统的开发: + +- 本系统将在windows上开发,采用python语言和PyQT技术进行图形界面的开发。深度学习框架使用pytorch。 +- 系统功能:可视化地展示模型的训练过程和语音情感的识别过程。拟实现一个抑郁症患者情绪跟踪管理系统,比如日常性对病人发送问题,根据患者的回答进行情感分析,辅助医生分析患者病情走势 + +--- + +各部分间的关系 +![ 在这里插入图片描述](https://img-blog.csdnimg.cn/10f77de059604bd8be125e1dd3c39d55.png) + +## 系统开发 + +![image-20230510185320088](D:\repos\CCSER\SER\assets\image-20230510185320088.png) + +## 总结 + +- + + + + + diff --git a/release_note.md b/release_note.md index 8ccaaa23c40a054be3d0c589ec9a65fe5826ebf7..4f69c043d8531badb440060e7d3c5d1e9d6bef2a 100644 --- a/release_note.md +++ b/release_note.md @@ -23,7 +23,17 @@ - **input version under this line:** - new notes:"Sort update records in descending order of time".That would be convenient to update new version notes in the future. -- +- *current modifing:* + - ... + +- 2023-05-10@20:06:02 + - initially support the interface language switch:between Chinese and English + - the approch to achieve the multilanguage support depending on language string resource py file: + - `zh.py` for Chinese + - `en.py` for english + - for convenience,these module was managed by the `multilanguage.py`module. + - unfortunately,these features was test in `fviewer.py`,the main gui was still unable to work normally because the `windows.close` caused the program broken! + - improve the regex_filter performance by using `re.compile` instead `re.` - 2023-05-09@19:10:05 - fix some bugs. - certain adjustments to the project code. diff --git a/test_playground/__pycache__/m1.cpython-39.pyc b/test_playground/__pycache__/m1.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e1eb7428398c5e12cce9b6130a528efc4948c939 Binary files /dev/null and b/test_playground/__pycache__/m1.cpython-39.pyc differ diff --git a/test_playground/m1.py b/test_playground/m1.py new file mode 100644 index 0000000000000000000000000000000000000000..34fc50231d7af16ea0ba6baa3504eac53540407c --- /dev/null +++ b/test_playground/m1.py @@ -0,0 +1,3 @@ +var=100 +def check_var(): + print(var,"@{var}",__file__) \ No newline at end of file diff --git a/test_playground/m2.py b/test_playground/m2.py new file mode 100644 index 0000000000000000000000000000000000000000..753298dc7628b94efe07efa3ed48d60d4e3906ed --- /dev/null +++ b/test_playground/m2.py @@ -0,0 +1,5 @@ +import m1 +m1.var=1 +m1.check_var() + +# print(m1.var,"@{m1.var}") \ No newline at end of file