import os.path import re import gradio as gr from functools import partial from .main_page import sort_with_pyuca def split_intro_text(intro_text): lines = intro_text.strip().split("\n") if lines and lines[0].startswith("#"): title = lines[0] body = "\n".join(lines[1:]) return title, body return "", intro_text # Basic, permissive email format check (local@domain.tld). Used only to gate the # "Continue" button so users don't proceed with an obviously malformed address. _EMAIL_RE = re.compile(r"^[^@\s]+@[^@\s]+\.[^@\s]+$") def _looks_like_email(value): return bool(_EMAIL_RE.match((value or "").strip())) def update_language_options(selected_country, metadata): with open(metadata["USA"]["English"]["Intro"], "r", encoding="utf-8") as f: INTRO_TEXT = f.read() # default # Retrieve the list of languages available for the selected country. if selected_country in metadata: languages = sort_with_pyuca(list(metadata[selected_country].keys())) if len(languages) == 0: gr.Warning("No languages available for the selected country.") t, b = split_intro_text(INTRO_TEXT) return gr.update(choices=[], interactive=False, value=None), gr.update(value=t), gr.update(value=b) # select the first language as default fn = metadata[selected_country][languages[0]]["Intro"] if os.path.exists(fn): with open(fn, "r", encoding="utf-8") as f: INTRO_TEXT = f.read() # Use gr.Dropdown.update to change the choices of the language dropdown. val = languages[0] if len(languages) == 1 else None t, b = split_intro_text(INTRO_TEXT) return gr.update(choices=languages, interactive=True, value=val, allow_custom_value=False), gr.update(value=t), gr.update(value=b) else: t, b = split_intro_text(INTRO_TEXT) return gr.update(choices=[], interactive=False, value=None, allow_custom_value=False), gr.update(value=t), gr.update(value=b) def enable_country(): return gr.update(interactive=True) def update_profile_button_state(email): email = (email or "").strip() valid = _looks_like_email(email) # Reveal the primary "Continue" button as soon as the user starts typing an # email, but only enable it once the address looks valid. HF login auto-fills # a valid email, so this enables Continue automatically in that path too. return gr.update(interactive=valid, visible=bool(email)) def prefill_country_language(saved_country, saved_language, current_country, current_language, metadata): """ Build updates for country/language dropdowns from persisted values. Country is set first so the existing country->language cascade remains valid. """ if current_country: return ( gr.skip(), gr.skip(), gr.skip(), gr.skip(), ) countries = sort_with_pyuca(list(metadata.keys())) if not saved_country or saved_country not in metadata: return ( gr.skip(), gr.skip(), gr.skip(), gr.skip(), ) # Compute language options directly to avoid relying on component instance attrs. valid_languages = sort_with_pyuca(list(metadata[saved_country].keys())) final_language = saved_language if saved_language in valid_languages else (valid_languages[0] if len(valid_languages) == 1 else None) fn = metadata[saved_country][valid_languages[0]]["Intro"] if valid_languages else metadata["USA"]["English"]["Intro"] intro_text = "" if os.path.exists(fn): with open(fn, "r", encoding="utf-8") as f: intro_text = f.read() if intro_text: t, b = split_intro_text(intro_text) return ( gr.update(choices=countries, value=saved_country, interactive=True), gr.update(choices=valid_languages, value=final_language, interactive=True), gr.update(value=t), gr.update(value=b), ) return ( gr.update(choices=countries, value=saved_country, interactive=True), gr.update(choices=valid_languages, value=final_language, interactive=True), gr.skip(), gr.skip(), ) def build_selection_page(metadata_dict): with gr.Column(visible=True, elem_classes=["compact-container"]) as selection_page: with open(metadata_dict["USA"]["English"]["Intro"], "r", encoding="utf-8") as f: INTRO_TEXT = f.read() title, body = split_intro_text(INTRO_TEXT) intro_title = gr.Markdown(title) # Locale choice dropdowns next to each other countries = sort_with_pyuca(list(metadata_dict.keys())) with gr.Row(): country_choice = gr.Dropdown( choices=countries, label="Country", allow_custom_value=False, value=None, interactive=True, ) language_choice = gr.Dropdown( choices=[], label="Language", allow_custom_value=False, interactive=False, # Initially disabled. ) intro_body = gr.Markdown(body) with gr.Column(visible=True) as signin_section: signin_title = gr.Markdown("## Please select your profile") login_btn = gr.LoginButton("Sign in with Hugging Face (optional)") # TODO: Multilingual user_name = gr.Markdown("", visible=False) username = gr.Markdown("", visible=False) email_inp = gr.Textbox( label="Email", type="email", placeholder="you@example.com", info="Add your email to save your work and review or edit it later.", ) # Primary call-to-action. Hidden until the user starts entering an # email and only enabled for a valid address (see # update_profile_button_state). HF login auto-fills the email. prof_btn = gr.Button("Continue", variant="primary", visible=False, interactive=False) # Secondary, de-emphasized escape hatch with an explicit consequence # so the trade-off of anonymous submissions is clear up front. anon_note = gr.Markdown( "" "Prefer not to log in? You can continue anonymously, but you won't be able to review, edit, or delete your submissions later. " "Also, at the end of the data collection campaign, we will use account information to create a list of all contributors and provide rewards to the best ones. " "For details, see our website [https://team-wonders.github.io/](https://team-wonders.github.io/)." "" ) anon_btn = gr.Button("Proceed as Anonymous", variant="secondary", size="sm") with gr.Column(visible=False) as selection_section: selection_title = gr.Markdown("## Please select your country", visible=False) proceed_btn = gr.Button("Annotate", variant="primary", visible=False) # When the country selection changes, update the language dropdown. country_choice.change( fn=partial(update_language_options, metadata=metadata_dict), inputs=country_choice, outputs=[language_choice, intro_title, intro_body] ) # Event listeners # username.change( # fn=enable_country, # outputs=[country_choice], # ) email_inp.change( fn=update_profile_button_state, inputs=[email_inp], outputs=[prof_btn], ) # with gr.Row(): # username = gr.Textbox(label="Email (optional)", type="email", elem_id="username_text") # password = gr.Textbox(label="Password (optional)", type="password", elem_id="password_text") # with gr.Row(): # login_btn = gr.Button("Login", elem_id="login_btn") # sign_up_btn = gr.Button("Sign up", elem_id="sign_up_btn") # reset_password_btn = gr.Button("Reset Password", elem_id="reset_password_btn") # logout_btn = gr.Button("Logout", elem_id="logout_btn",visible=False) # gr.Markdown("### Choose how you want to continue") # with gr.Row(): # login_btn = gr.LoginButton("Sign in with Hugging Face") # TODO: Multilingual # anon_btn = gr.Button("Proceed as Anonymous") # username = gr.Markdown("", visible=False) # login_status = gr.Markdown("") # with gr.Row(): # change_password_field = gr.Textbox( # label="Change Password", type="password", elem_id="change_password_field", visible=True # ) # change_password_field_confirm = gr.Textbox( # label="Confirm New Password", type="password", elem_id="change_password_field_confirm", visible=True # ) # with gr.Row(): # change_password_btn = gr.Button("Change Password", elem_id="change_password_btn", visible=True) # change_password_status = gr.Markdown("") return ( selection_page, country_choice, language_choice, proceed_btn, anon_btn, login_btn, prof_btn, username, user_name, email_inp, intro_title, intro_body, signin_title, selection_title, signin_section, selection_section, )