Spaces:
Running
Running
import gradio as gr | |
from logic.data_utils import CustomHFDatasetSaver | |
from data.lang2eng_map import lang2eng_mapping | |
from gradio_modal import Modal | |
from logic.handlers import * | |
from config.settings import * | |
from functools import partial | |
from .selection_page import build_selection_page | |
from .main_page import build_main_page | |
def get_key_by_value(dictionary, value): | |
for key, val in dictionary.items(): | |
if val == value: | |
return key | |
return None | |
def load_concepts(category, concept_btn, local_storage, loading_example, concepts): | |
country, lang, _, _ = local_storage | |
if category: | |
if lang in words_mapping: | |
category = get_key_by_value(words_mapping[lang], category) # translate back the category name | |
concept_val = None | |
# I'm doing this to avoid the case where the user load a previous example and the concept 'reamins' selected even if category changed | |
if loading_example: | |
concept_val = concept_btn if concept_btn else None | |
return gr.update(choices=sorted(concepts[country][lang2eng_mapping.get(lang, lang)][category]), value=concept_val), False | |
else: | |
return gr.update(choices=[], value=None), False | |
def switch_ui(country, language, username, password, flag=False, metadata_dict=None): | |
print(f"Language: {language}, Country: {country}") | |
# Hide the selection page and show the main UI. | |
if flag: | |
local_storage = [None, None, "", ""] | |
return (local_storage, gr.update(visible=flag), gr.update(visible=not flag), | |
gr.update(visible=not flag), | |
gr.update(choices=list(metadata_dict.keys()), label="Country", value=None), | |
gr.update(value=None, choices=[], label="Language", allow_custom_value=False, interactive=False)) | |
else: | |
local_storage = [country, language, username, password] | |
return local_storage, gr.update(visible=flag), gr.update(visible=not flag), gr.update(visible=not flag) | |
def build_ui(concepts_dict, metadata_dict, HF_API_TOKEN, HF_DATASET_NAME): | |
hf_writer = CustomHFDatasetSaver(HF_API_TOKEN, HF_DATASET_NAME, private=True) | |
custom_css = """ | |
.compact-container { | |
max-width: 600px; | |
margin: auto; | |
padding: 20px; | |
} | |
.compact-btn { | |
} | |
""" | |
with gr.Blocks(css=custom_css) as ui: | |
local_storage = gr.State([None, None, "", ""]) | |
loading_example = gr.State(False) # to check if the values are loaded from a user click on an example in | |
# First page: selection | |
selection_page, country_choice, language_choice, proceed_btn, username, password, intro_markdown = build_selection_page(metadata_dict) | |
# Second page | |
cmp_main_ui = build_main_page(concepts_dict, metadata_dict, local_storage) | |
main_ui_placeholder = cmp_main_ui["main_ui_placeholder"] | |
country_inp = cmp_main_ui["country_inp"] | |
language_inp = cmp_main_ui["language_inp"] | |
image_inp = cmp_main_ui["image_inp"] | |
image_url_inp = cmp_main_ui["image_url_inp"] | |
long_caption_inp = cmp_main_ui["long_caption_inp"] | |
category_btn = cmp_main_ui["category_btn"] | |
concept_btn = cmp_main_ui["concept_btn"] | |
category_concept_dropdowns = cmp_main_ui["category_concept_dropdowns"] | |
instruct_btn = cmp_main_ui["instruct_btn"] | |
clear_btn = cmp_main_ui["clear_btn"] | |
hide_faces_btn = cmp_main_ui["hide_faces_btn"] | |
hide_all_faces_btn = cmp_main_ui["hide_all_faces_btn"] | |
unhide_faces_btn = cmp_main_ui["unhide_faces_btn"] | |
submit_btn = cmp_main_ui["submit_btn"] | |
timestamp_btn = cmp_main_ui["timestamp_btn"] | |
exampleid_btn = cmp_main_ui["exampleid_btn"] | |
username_inp = cmp_main_ui["username_inp"] | |
password_inp = cmp_main_ui["password_inp"] | |
modal_saving = cmp_main_ui["modal_saving"] | |
modal_data_saved = cmp_main_ui["modal_data_saved"] | |
modal = cmp_main_ui["modal"] | |
exit_btn = cmp_main_ui["exit_btn"] | |
intro_text_inp = cmp_main_ui["intro_text_inp"] # Note intro_text is actually the "Task" text from metadata | |
intro_text_inst_inp = cmp_main_ui["intro_text_inst_inp"] # This is the "Instructions" text from metadata | |
modal_saving_text = cmp_main_ui["modal_saving_text"] | |
modal_data_saved_text = cmp_main_ui["modal_data_saved_text"] | |
exclude_btn = cmp_main_ui["exclude_btn"] | |
modal_exclude_confirm = cmp_main_ui["modal_exclude_confirm"] | |
cancel_exclude_btn = cmp_main_ui["cancel_exclude_btn"] | |
confirm_exclude_btn = cmp_main_ui["confirm_exclude_btn"] | |
### Category button | |
category_btn.change( | |
fn=partial(load_concepts, concepts=concepts_dict), | |
inputs=[category_btn, concept_btn, local_storage, loading_example], | |
outputs=[concept_btn, loading_example] | |
) | |
#### | |
# is_blurred = gr.State(False) # Initialize as False | |
# Notification image is false | |
with Modal(visible=False) as modal_img_url: | |
gr.Markdown("The image URL is not valid. Please provide a valid image URL.") | |
# gr.Warning(f"⚠️ The image URL is not valid. Please provide a valid image URL.") | |
# Event listeners | |
gr.on( | |
triggers=[image_url_inp.change], | |
fn=update_image, | |
inputs=[image_url_inp], | |
outputs=[image_inp, modal_img_url] | |
) | |
gr.on( | |
triggers=[language_choice.change], | |
fn=partial(update_intro_language, metadata=metadata_dict), | |
inputs=[country_choice, language_choice, intro_markdown], | |
outputs=[intro_markdown] | |
) | |
gr.on( | |
triggers=[image_inp.change, long_caption_inp.change], | |
fn=update_timestamp, | |
outputs=[timestamp_btn] | |
) | |
ori_img = gr.State(None) | |
gr.on( | |
triggers=[image_inp.change], | |
fn=validate_inputs, | |
inputs=[image_inp, ori_img], # is_blurred | |
outputs=[submit_btn, image_inp, ori_img], # is_blurred | |
) | |
# Clear Button | |
clear_btn.click( | |
fn=clear_data, | |
outputs=[ | |
image_inp, image_url_inp, long_caption_inp, exampleid_btn, | |
category_btn, concept_btn, | |
category_concept_dropdowns[0], category_concept_dropdowns[1], category_concept_dropdowns[2], | |
category_concept_dropdowns[3], category_concept_dropdowns[4] | |
], | |
) | |
#============= Face Blurring ============= # | |
with Modal(visible=False) as modal_faces: | |
with gr.Column(): | |
face_img = gr.Image(label="Image Faces", elem_id="image_faces", format="png", height=512, width=768) | |
with gr.Row(): | |
faces_count = gr.Textbox(label="Face Counts", elem_id="face_counts", interactive=False) | |
blur_faces_ids = gr.Dropdown( | |
[], value=[], multiselect=True, label="Please select the faces IDs you want to blur.", elem_id="blur_faces_ids") | |
# blur_faces_ids = gr.Textbox(label="Specify faces ids to blur by comma", elem_id="blur_faces_ids", interactive=True) | |
submit_btn_face = gr.Button("Submit", variant="primary", interactive=True, elem_id="submit_btn_face") | |
with Modal(visible=False) as modal_faces_2: | |
gr.Markdown("The current image does not have any faces to hide.") | |
faces_info = gr.State(None) | |
hide_faces_btn.click( | |
fn=select_faces_to_hide, | |
inputs=[image_inp, blur_faces_ids], | |
outputs=[image_inp, modal_faces, modal_faces_2, face_img, faces_count, faces_info, blur_faces_ids] | |
) | |
submit_btn_face.click( | |
fn=blur_selected_faces, | |
inputs=[image_inp, blur_faces_ids, faces_info, face_img, faces_count], # is_blurred | |
outputs=[image_inp, modal_faces, face_img, faces_count, blur_faces_ids] # is_blurred | |
) | |
hide_all_faces_btn.click( | |
fn=blur_all_faces, | |
inputs=[image_inp], | |
outputs=[image_inp, modal_faces_2] # is_blurred | |
) | |
unhide_faces_btn.click( | |
fn=unhide_faces, | |
inputs=[image_inp, ori_img], # is_blurred | |
outputs=[image_inp] # is_blurred | |
) | |
# =============================== | |
with gr.Column(visible=False, elem_id="browse_data") as browse_data_placeholder: | |
# Browse Data | |
browse_data_text = gr.Markdown("## Browse Data") | |
loading_msg = gr.Markdown("**Loading your data, please wait ...**") | |
for contrib_type in ["Your data", "Other data"]: | |
with gr.Tab(contrib_type): | |
if contrib_type == "Your data": | |
# Show user's past data points | |
user_examples = gr.Dataset( | |
samples=[], | |
components=['image','textbox','textbox','textbox','textbox', | |
'textbox','textbox','textbox', 'textbox'], | |
headers=['Image', 'Image URL (Optional, if not uploading an image)', 'Description', 'Country', 'Language', | |
'Category', 'Concept', 'Additional Concepts', 'ID'], | |
) | |
# Handle clicking on an example | |
user_examples.click( | |
fn=partial(handle_click_example, concepts_dict=concepts_dict), | |
inputs=[user_examples], | |
outputs=[ | |
image_inp, image_url_inp, long_caption_inp, exampleid_btn, | |
category_btn, concept_btn, | |
category_concept_dropdowns[0], category_concept_dropdowns[1], category_concept_dropdowns[2], | |
category_concept_dropdowns[3], category_concept_dropdowns[4], loading_example | |
], | |
) | |
elif contrib_type == "Other data": | |
# Show others' images | |
pass | |
# ============================================ # | |
# Submit Button Click events | |
proceed_btn.click( | |
fn=partial(switch_ui, flag=False), | |
inputs=[country_choice, language_choice, username, password], | |
outputs=[local_storage, selection_page, main_ui_placeholder, browse_data_placeholder], | |
).then( | |
fn=partial(update_language, metadata_dict=metadata_dict, concepts_dict=concepts_dict), | |
inputs=[local_storage], | |
outputs=[ | |
country_inp, language_inp, username_inp, password_inp, category_btn, concept_btn, image_inp, | |
image_url_inp, long_caption_inp, intro_text_inp, intro_text_inst_inp, instruct_btn, clear_btn, | |
submit_btn, modal_saving_text, modal_data_saved_text, timestamp_btn, exit_btn, browse_data_text, | |
loading_msg, hide_all_faces_btn, hide_faces_btn, unhide_faces_btn, exclude_btn, | |
category_concept_dropdowns[0], category_concept_dropdowns[1], category_concept_dropdowns[2], | |
category_concept_dropdowns[3], category_concept_dropdowns[4] | |
] | |
).then( | |
fn=partial(update_user_data, HF_DATASET_NAME=HF_DATASET_NAME, local_ds_directory_path = LOCAL_DS_DIRECTORY_PATH), | |
inputs=[username_inp, password_inp, country_choice, language_choice], | |
outputs=[user_examples, loading_msg], | |
) | |
# Exit Button | |
exit_btn.click( | |
fn=exit, | |
outputs=[ | |
image_inp, image_url_inp, long_caption_inp, user_examples, loading_msg, | |
username, password, local_storage, exampleid_btn, category_btn, concept_btn, | |
category_concept_dropdowns[0], category_concept_dropdowns[1], category_concept_dropdowns[2], | |
category_concept_dropdowns[3], category_concept_dropdowns[4] | |
], | |
).then( | |
fn=partial(switch_ui, flag=True, metadata_dict=metadata_dict), | |
inputs=[country_choice, language_choice, username, password], | |
outputs=[local_storage, selection_page, main_ui_placeholder, browse_data_placeholder, country_choice, language_choice], | |
) | |
# Disable button while saving | |
# Note: I think this is not longer needed as we clear all the inputs and disable the submit button if the data is saved correctly | |
# def disable_submit(): | |
# return gr.update(interactive=False) | |
# def enable_submit(): | |
# return gr.update(interactive=True) | |
# STEP 1: show modal | |
# submit_btn.click(lambda: Modal(visible=True), None, modal_saving) | |
# STEP 2: disable button | |
# submit_btn.click(disable_submit, None, [submit_btn], queue=False) | |
#STEP 3: perform save_data | |
data_outputs = { | |
"image": image_inp, | |
"image_url": image_url_inp, | |
"caption": long_caption_inp, | |
"country": country_inp, | |
"language": language_inp, | |
"category": category_btn, | |
"concept": concept_btn, | |
"category_1_concepts": category_concept_dropdowns[0], | |
"category_2_concepts": category_concept_dropdowns[1], | |
"category_3_concepts": category_concept_dropdowns[2], | |
"category_4_concepts": category_concept_dropdowns[3], | |
"category_5_concepts": category_concept_dropdowns[4], | |
"timestamp": timestamp_btn, | |
"username": username_inp, | |
"password": password_inp, | |
"id": exampleid_btn, | |
"excluded": gr.State(value=False), | |
"concepts_dict": gr.State(value=concepts_dict), | |
"country_lang_map": gr.State(value=lang2eng_mapping), | |
# "is_blurred": is_blurred | |
} | |
# data_outputs = [image_inp, image_url_inp, long_caption_inp, | |
# country_inp, language_inp, category_btn, concept_btn, | |
# timestamp_btn, username_inp, password_inp, exampleid_btn] | |
hf_writer.setup(list(data_outputs.keys()), local_ds_folder = LOCAL_DS_DIRECTORY_PATH) | |
# STEP 4: Chain save_data, then update_user_data, then re-enable button, hide modal, and clear | |
submit_btn.click( | |
hf_writer.save, | |
list(data_outputs.values()), | |
None, | |
).success( | |
fn=clear_data, | |
outputs=[ | |
image_inp, image_url_inp, long_caption_inp, exampleid_btn, | |
category_btn, concept_btn, | |
category_concept_dropdowns[0], category_concept_dropdowns[1], category_concept_dropdowns[2], | |
category_concept_dropdowns[3], category_concept_dropdowns[4] | |
], | |
# ).success(enable_submit, | |
# None, [submit_btn] | |
# ).success(lambda: Modal(visible=False), | |
# None, modal_saving | |
# ).success(lambda: Modal(visible=True), | |
# None, modal_data_saved | |
).success( | |
# set loading msg | |
lambda: gr.update(value="**Loading your data, please wait ...**"), | |
None, loading_msg | |
).success( | |
fn=partial(update_user_data, HF_DATASET_NAME=HF_DATASET_NAME, local_ds_directory_path = LOCAL_DS_DIRECTORY_PATH), | |
inputs=[username_inp, password_inp, country_choice, language_choice], | |
outputs=[user_examples, loading_msg] | |
) | |
# ============================================ # | |
# instructions button | |
instruct_btn.click(lambda: Modal(visible=True), None, modal) | |
# ============================================ # | |
# # Load saved values from local storage (browser storage) | |
# @ui.load(inputs=[local_storage], outputs=[country_choice, language_choice, username, password]) | |
# def load_from_local_storage(saved_values): | |
# print("loading from local storage", saved_values) | |
# return saved_values[0], saved_values[1], saved_values[2], saved_values[3] | |
# ============================================= # | |
# Exclude button | |
# ============================================= # | |
exclude_status = gr.Markdown(visible=False) | |
# Show confirmation modal when exclude button is clicked | |
exclude_btn.click( | |
fn=check_exclude_fn, | |
inputs=[image_inp], | |
outputs=[modal_exclude_confirm] | |
) | |
# Close modal when cancel button is clicked | |
cancel_exclude_btn.click( | |
fn=lambda: gr.update(visible=False), | |
outputs=[modal_exclude_confirm] | |
) | |
# Handle confirm exclusion | |
confirm_exclude_btn.click( | |
fn=lambda: gr.update(visible=False), | |
outputs=[modal_exclude_confirm] | |
).success( | |
fn=hf_writer.save, | |
inputs=[ | |
image_inp, image_url_inp, long_caption_inp, country_inp, language_inp, | |
category_btn, concept_btn, | |
category_concept_dropdowns[0], category_concept_dropdowns[1], category_concept_dropdowns[2], | |
category_concept_dropdowns[3], category_concept_dropdowns[4], | |
timestamp_btn, username_inp, password_inp, exampleid_btn, gr.State(value=True), | |
gr.State(value=concepts_dict), gr.State(value=lang2eng_mapping) | |
], | |
outputs=None | |
).success( | |
fn=clear_data, | |
outputs=[ | |
image_inp, image_url_inp, long_caption_inp, exampleid_btn, | |
category_btn, concept_btn, | |
category_concept_dropdowns[0], category_concept_dropdowns[1], category_concept_dropdowns[2], | |
category_concept_dropdowns[3], category_concept_dropdowns[4] | |
] | |
).success( | |
fn=lambda: gr.update(value="Example excluded successfully", visible=True), | |
outputs=exclude_status | |
).success( | |
fn=lambda: gr.update(value="**Refreshing your data, please wait...**"), | |
outputs=loading_msg | |
).success( | |
fn=partial(update_user_data, HF_DATASET_NAME=HF_DATASET_NAME, local_ds_directory_path=LOCAL_DS_DIRECTORY_PATH), | |
inputs=[username_inp, password_inp, country_choice, language_choice], | |
outputs=[user_examples, loading_msg] | |
) | |
return ui |