import gradio as gr import pandas as pd import os import hashlib from datasets import Dataset, concatenate_datasets, load_dataset from huggingface_hub import login # ============================ # CONFIGURATION # ============================ AUDIO_FOLDER = "audio_files" audio_files = sorted(os.listdir(AUDIO_FOLDER)) ADMIN_PASSWORD_HASH = "eb32da077dfaf326cd6f73e0716b628da6427aa318a2d0b9fafa9ef315b5e885" # ============================ # HF DATASET CONFIGURATION # ============================ HF_DATASET_NAME = "MeysamSh/Annotate_Samples" # replace with your HF dataset HF_TOKEN = os.environ.get("HF_TOKEN") # store your token as a secret in Spaces login(HF_TOKEN) # ============================ # USER FUNCTIONS # ============================ def load_hf_dataset(): """Load existing HF Dataset or create empty one if not exists.""" try: ds = load_dataset(HF_DATASET_NAME, split="train") except: # Dataset does not exist yet df = pd.DataFrame(columns=["user_id", "gender", "audio_file", "score"]) ds = Dataset.from_pandas(df) ds.push_to_hub(HF_DATASET_NAME, private=True) return ds def submit_annotation_hf(user_id, gender, score, audio_file): """Append annotation to HF Dataset.""" ds = load_hf_dataset() new_row = pd.DataFrame([{ "user_id": user_id, "gender": gender, "audio_file": audio_file, "score": score }]) ds_new = Dataset.from_pandas(new_row) ds_combined = concatenate_datasets([ds, ds_new]) ds_combined.push_to_hub(HF_DATASET_NAME) def load_next_audio(state): if state is None: state = {"index": 0} idx = state["index"] if idx >= len(audio_files): return None, state, {"played": 0}, "All audio files annotated." filepath = os.path.join(AUDIO_FOLDER, audio_files[idx]) return filepath, state, {"played": 0}, f"Loaded {audio_files[idx]}" def submit_annotation(user_id, gender, score, state): if state is None: state = {"index": 0} idx = state["index"] if idx >= len(audio_files): return state, "No more audio files." audio_file = audio_files[idx] submit_annotation_hf(user_id, gender, score, audio_file) state["index"] += 1 return state, f"Saved rating for {audio_file}." # ============================ # SUBMIT BUTTON CONTROL # ============================ def check_submit_ready(user_id, audio_played, score): ready = len(user_id.strip()) > 1 and audio_played['played'] == 1 and score != "None" return gr.update(interactive=ready) def mark_audio_played(): return {"played": 1} # ============================ # ADMIN FUNCTIONS # ============================ def hash_password(password: str) -> str: return hashlib.sha256(password.encode()).hexdigest() def admin_login(input_password): if hash_password(input_password) == ADMIN_PASSWORD_HASH: ds = load_hf_dataset() df = ds.to_pandas() # For download: write temp CSV temp_csv = "annotations_export.csv" df.to_csv(temp_csv, index=False) return ( gr.update(visible=True), df, temp_csv, gr.update(value="Admin authentication successful.") ) else: return ( gr.update(visible=False), None, None, gr.update(value="Admin authentication failed.") ) # ============================ # GRADIO UI # ============================ with gr.Blocks() as demo: gr.Markdown("# Audio MOS Annotation Tool") # -------------------------- # USER SECTION # -------------------------- state = gr.State({"index": 0}) audio_played = gr.State({"played": 0}) with gr.Row(): user_id = gr.Textbox(label="User ID") gender = gr.Dropdown(["Male", "Female", "Other"], label="Gender", value="Other") audio_player = gr.Audio(label="Audio File") with gr.Row(): score = gr.Dropdown(choices=["None","1", "2", "3", "4", "5"], value="None", label="MOS Score (1–5)") submit_btn = gr.Button("Submit Score", interactive=False) status = gr.Textbox(label="Status", interactive=False) # Load first audio demo.load( load_next_audio, inputs=state, outputs=[audio_player, state, audio_played, status] ) # Mark audio as played audio_player.play( mark_audio_played, None, audio_played ) # Enable submit button only when conditions are met user_id.change( check_submit_ready, inputs=[user_id, audio_played, score], outputs=submit_btn ) audio_played.change( check_submit_ready, inputs=[user_id, audio_played, score], outputs=submit_btn ) score.change( check_submit_ready, inputs=[user_id, audio_played, score], outputs=submit_btn ) # Save annotation submit_btn.click( submit_annotation, inputs=[user_id, gender, score, state], outputs=[state, status] ) # Load next audio submit_btn.click( load_next_audio, inputs=state, outputs=[audio_player, state, audio_played, status] ) # ============================ # ADMIN DASHBOARD # ============================ gr.Markdown("## Admin Dashboard (Restricted Access)") with gr.Row(): admin_password = gr.Textbox(label="Admin Password", type="password") admin_login_btn = gr.Button("Login") login_status = gr.Textbox(label="Login Status:", interactive=False) with gr.Column(visible=False) as admin_panel: gr.Markdown("### Annotation Results") pd_loaded=load_hf_dataset().to_pandas() results_table = gr.DataFrame(interactive=False, value=pd_loaded) pd_loaded.to_csv("annotations_export.csv", index=False) download_admin = gr.File(label="Download annotations.csv", value="annotations_export.csv") admin_login_btn.click( admin_login, inputs=admin_password, outputs=[admin_panel, results_table, download_admin, login_status] ) # ============================ # APP LAUNCH # ============================ if __name__ == "__main__": demo.launch()