Spaces:
Running
Running
| import gradio as gr | |
| import pandas as pd | |
| import os | |
| import hashlib | |
| # ============================ | |
| # CONFIGURATION | |
| # ============================ | |
| AUDIO_FOLDER = "audio_files" | |
| audio_files = sorted(os.listdir(AUDIO_FOLDER)) | |
| ANNOTATION_FILE = "annotations.csv" | |
| ADMIN_PASSWORD_HASH = "eb32da077dfaf326cd6f73e0716b628da6427aa318a2d0b9fafa9ef315b5e885" | |
| # ============================ | |
| # STORAGE INITIALIZATION | |
| # ============================ | |
| if not os.path.exists(ANNOTATION_FILE): | |
| df = pd.DataFrame(columns=["user_id", "gender", "audio_file", "score"]) | |
| df.to_csv(ANNOTATION_FILE, index=False) | |
| # ============================ | |
| # USER FUNCTIONS | |
| # ============================ | |
| def load_next_audio(state): | |
| if state is None: | |
| state = {"index": 0} | |
| idx = state["index"] | |
| if idx >= len(audio_files): | |
| return None, state, False, "All audio files annotated." | |
| filepath = os.path.join(AUDIO_FOLDER, audio_files[idx]) | |
| # return filepath, state, False, f"Loaded {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] | |
| df = pd.read_csv(ANNOTATION_FILE) | |
| df = pd.concat([df, pd.DataFrame([{ | |
| "user_id": user_id, | |
| "gender": gender, | |
| "audio_file": audio_file, | |
| "score": score | |
| }])], ignore_index=True) | |
| df.to_csv(ANNOTATION_FILE, index=False) | |
| 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: | |
| df = pd.read_csv(ANNOTATION_FILE) | |
| return ( | |
| gr.update(visible=True), | |
| df, | |
| ANNOTATION_FILE, | |
| gr.update(value="Admin authentication successful.") | |
| ) | |
| else: | |
| return ( | |
| gr.update(visible=False), | |
| None, | |
| None, | |
| gr.update(value="Admin authentication successful.") | |
| ) | |
| # ============================ | |
| # 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") | |
| results_table = gr.DataFrame(interactive=False) | |
| download_admin = gr.File(label="Download annotations.csv") | |
| admin_login_btn.click( | |
| admin_login, | |
| inputs=admin_password, | |
| outputs=[admin_panel, results_table, download_admin, login_status] | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch(share=True) | |
| # demo.launch(server_name="0.0.0.0", server_port=7860) | |
| # demo.launch(server_name="0.0.0.0", server_port=7860, prevent_thread_lock=True) | |