"""Policy definition tab UI components.""" import os import sys import gradio as gr sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from utils.helpers import load_policy_from_file, load_preset_policy def build_policy_tab(base_dir: str) -> dict: """Build the policy definition tab UI.""" with gr.Tab("📋 Policy Definition"): current_policy_state = gr.State(value="") uploaded_policies_state = gr.State(value={}) # Store uploaded policies: {"Uploaded - filename": content} # Existing Policy Accordion with gr.Accordion("📥 Load Existing Policy", open=False): with gr.Row(): with gr.Column(): preset_dropdown = gr.Dropdown( label="Select Preset", choices=["Hate Speech Policy", "Violence Policy", "Toxicity Policy"], value=None ) load_preset_btn = gr.Button("Load Preset") credit_markdown = gr.Markdown("**Credit:** The example policies were taken from the [Zentropi website](https://zentropi.ai/labelers).") with gr.Column(): gr.Markdown("Upload a markdown file:") upload_file = gr.File(label="Upload Markdown File", file_types=[".md"]) # Manual Edition Accordion with gr.Accordion("✏️ Manual Editing", open=False): manual_text = gr.Textbox( label="Policy Text", placeholder="Enter or edit policy markdown...", lines=20 ) policy_preview = gr.Markdown(value="*No policy loaded*") # Clear button clear_policy_btn = gr.Button("Clear Policy", variant="secondary") # Handlers def load_preset_handler(name, uploaded_policies): """Load policy from preset or uploaded policies.""" if not name: return "", "*No policy loaded*", "" # Check presets first preset_choices = ["Hate Speech Policy", "Violence Policy", "Toxicity Policy"] if name in preset_choices: policy_text, _ = load_preset_policy(name, base_dir) return policy_text, policy_text, policy_text # Check uploaded policies if name in uploaded_policies: policy_text = uploaded_policies[name] return policy_text, policy_text, policy_text return "", "*No policy loaded*", "" load_preset_btn.click( load_preset_handler, inputs=[preset_dropdown, uploaded_policies_state], outputs=[current_policy_state, manual_text, policy_preview], ) def load_upload_handler(f, uploaded_policies): """Handle file upload: load policy, store it, and update dropdown.""" if not f: return "", "", "*No policy loaded*", gr.update(), {} # Extract filename filename = os.path.basename(f.name) upload_key = f"Uploaded - {filename}" # Load policy content policy_text, _ = load_policy_from_file(f.name) # Ensure uploaded_policies is a dict (handle case where it might be None) if uploaded_policies is None: uploaded_policies = {} # Check for duplicate BEFORE storing is_duplicate = upload_key in uploaded_policies # Store policy in state (overwrites if duplicate) uploaded_policies[upload_key] = policy_text # Build updated choices: presets + uploaded policies preset_choices = ["Hate Speech Policy", "Violence Policy", "Toxicity Policy"] all_choices = preset_choices + sorted(uploaded_policies.keys()) # Show warning if duplicate (gr.Warning is a function, not an exception) if is_duplicate: gr.Warning(f"Policy '{filename}' already uploaded. Previous version overwritten.") return ( policy_text, # current_policy_state policy_text, # manual_text policy_text, # policy_preview gr.update(choices=all_choices), # preset_dropdown uploaded_policies # uploaded_policies_state ) upload_file.change( load_upload_handler, inputs=[upload_file, uploaded_policies_state], outputs=[current_policy_state, manual_text, policy_preview, preset_dropdown, uploaded_policies_state], ) def update_preview(text): return text if text else "*No policy loaded*" # Update state and preview when user leaves the textbox (blur event) manual_text.blur( lambda t: (t, update_preview(t)), inputs=manual_text, outputs=[current_policy_state, policy_preview], ) clear_policy_btn.click( lambda: ("", "", "*No policy loaded*"), outputs=[current_policy_state, manual_text, policy_preview], ) # Sync UI components when state changes externally (e.g., from dataset load) def sync_policy_ui(policy_text): preview_text = policy_text if policy_text else "*No policy loaded*" return policy_text, preview_text current_policy_state.change( sync_policy_ui, inputs=current_policy_state, outputs=[manual_text, policy_preview], ) return { "current_policy_state": current_policy_state, }