import os from datetime import date from functools import lru_cache from urllib.parse import quote import gradio as gr import pandas as pd from gradio_client import Client SOURCE_SPACE_ID = os.getenv("SOURCE_SPACE_ID", "toecm/PurePolyglot") def _empty_df(columns): return pd.DataFrame(columns=columns) def _as_dataframe(value, columns=None): if isinstance(value, pd.DataFrame): return value if isinstance(value, dict): headers = value.get("headers") or columns or [] data = value.get("data") or [] return pd.DataFrame(data, columns=headers if headers else None) if isinstance(value, (list, tuple)): return pd.DataFrame(value, columns=columns) return _empty_df(columns or []) @lru_cache(maxsize=1) def polyglot_client(): return Client(SOURCE_SPACE_ID) def call_polyglot(api_name, *args): return polyglot_client().predict(*args, api_name=api_name) def call_first(api_names, *args): last_error = None for api_name in api_names: try: return call_polyglot(api_name, *args) except Exception as exc: last_error = exc raise RuntimeError(last_error) def refresh_pending(language_filter="All", dialect_filter="All", review_key=""): try: data = call_first( ["/get_pending_dataframe_2", "/get_pending_dataframe_1", "/get_pending_dataframe"], language_filter or "All", dialect_filter or "All", review_key or "", ) return _as_dataframe( data, [ "User", "Data_Origin", "Utterance", "Language", "Dialect", "Clarification", "Clarification_Source", "Tone", "Audio", "Timestamp", ], ) except Exception as exc: return _empty_df(["Error", "Detail"]).assign(Error=["Pending refresh failed"], Detail=[str(exc)]) def select_pending_row(evt: gr.SelectData, pending_table): df = _as_dataframe(pending_table) try: index = evt.index[0] if isinstance(evt.index, (list, tuple)) else evt.index row = df.iloc[int(index)] audio_path = str(row.get("Audio", "") or "") audio_name = os.path.basename(audio_path) audio_link = "" if audio_name: audio_url = "https://huggingface.co/datasets/toecm/PureChain_Dataset/resolve/main/pending_audio/" + quote(audio_name) audio_link = f"[Open pending audio]({audio_url})" return ( str(row.get("Timestamp", "") or ""), str(row.get("Utterance", "") or ""), str(row.get("Utterance", "") or ""), str(row.get("Language", "") or ""), str(row.get("Dialect", "") or ""), str(row.get("Clarification", "") or ""), str(row.get("Tone", "") or ""), audio_link, ) except Exception: return "", "", "", "", "", "", "", "" def approve_pending(timestamp, original, edited_utt, edited_lang, edited_dialect, edited_clar, edited_tone, audio_override, review_key, language_filter, dialect_filter): if not timestamp or not original: return "Select a pending row first.", refresh_pending(language_filter, dialect_filter, review_key) try: result = call_polyglot( "/admin_approve_pending", timestamp, original, edited_utt, edited_lang, edited_dialect, edited_clar, edited_tone, audio_override, review_key or "", ) return str(result), refresh_pending(language_filter, dialect_filter, review_key) except Exception as exc: return f"Approval failed: {exc}", refresh_pending(language_filter, dialect_filter, review_key) def reject_pending(timestamp, original, reason, custom_reason, review_key, language_filter, dialect_filter): if not timestamp or not original: return "Select a pending row first.", refresh_pending(language_filter, dialect_filter, review_key) try: result = call_polyglot("/admin_reject_pending", timestamp, original, reason, custom_reason, review_key or "") return str(result), refresh_pending(language_filter, dialect_filter, review_key) except Exception as exc: return f"Rejection failed: {exc}", refresh_pending(language_filter, dialect_filter, review_key) def clear_pending(review_key, language_filter, dialect_filter): try: result = call_polyglot("/admin_clear_all_pending", review_key or "") return str(result), refresh_pending(language_filter, dialect_filter, review_key) except Exception as exc: return f"Clear failed: {exc}", refresh_pending(language_filter, dialect_filter, review_key) def undo_last_admin_action(review_key, language_filter, dialect_filter): try: result = call_polyglot("/admin_undo_last_action", review_key or "") return str(result), refresh_pending(language_filter, dialect_filter, review_key) except Exception as exc: return f"Undo failed: {exc}", refresh_pending(language_filter, dialect_filter, review_key) def refresh_history(start_date, end_date, contract_filter, review_key=""): try: selected = contract_filter or ["PureBi"] data = call_polyglot("/run_filter", start_date, end_date, selected, review_key or "") return _as_dataframe( data, ["Timestamp", "Utterance", "Dialect", "Data_Origin", "Data_Approved", "Block", "TX Hash"], ) except Exception as exc: return _empty_df(["Error", "Detail"]).assign(Error=["History refresh failed"], Detail=[str(exc)]) def refresh_rejected(review_key=""): try: data = call_polyglot("/refresh_graveyard", review_key or "") return _as_dataframe(data, ["Utterance", "Dialect", "Rejection_Reason", "Rejector"]) except Exception as exc: return _empty_df(["Error", "Detail"]).assign(Error=["Rejected audit refresh failed"], Detail=[str(exc)]) def refresh_feedback(review_key=""): try: data = call_polyglot("/get_feedback_dataframe", review_key or "") return _as_dataframe(data, ["Timestamp", "Operator_ID", "Feedback_Text", "Image_Reference"]) except Exception as exc: return _empty_df(["Error", "Detail"]).assign(Error=["Feedback refresh failed"], Detail=[str(exc)]) def submit_feedback(operator_id, feedback_text, image_file, review_key=""): if not operator_id or not feedback_text: return "Operator ID and feedback text are required.", refresh_feedback(review_key) try: result = call_polyglot("/submit_feedback", operator_id, feedback_text, image_file) return str(result), refresh_feedback(review_key) except Exception as exc: return f"Feedback submit failed: {exc}", refresh_feedback(review_key) today = date.today().isoformat() with gr.Blocks(title="PureKITchat Admin Mirror") as demo: gr.Markdown("# PureKITchat Admin Mirror") admin_review_key = gr.Textbox(label="Reviewer/Admin passcode", type="password") with gr.Tabs(): with gr.Tab("Pending Audit/Approvals"): with gr.Row(): pending_language = gr.Textbox(value="All", label="Language Filter") pending_dialect = gr.Textbox(value="All", label="Dialect Filter") pending_refresh = gr.Button("Refresh Pending", variant="primary") pending_df = gr.Dataframe( value=_empty_df([ "User", "Data_Origin", "Utterance", "Language", "Dialect", "Clarification", "Clarification_Source", "Tone", "Audio", "Timestamp" ]), label="Pending submissions", interactive=False, wrap=False, ) with gr.Row(): timestamp = gr.Textbox(label="Timestamp ID", interactive=False) original_utt = gr.Textbox(label="Original Utterance", interactive=False) audio_link = gr.Markdown() with gr.Row(): edit_utt = gr.Textbox(label="Utterance") edit_lang = gr.Textbox(label="Language") edit_dialect = gr.Textbox(label="Dialect") with gr.Row(): edit_clar = gr.Textbox(label="Clarification") edit_tone = gr.Textbox(label="Tone") audio_override = gr.File(label="Optional trimmed audio override", type="filepath") with gr.Row(): approve_btn = gr.Button("Approve Selected", variant="primary") reject_reason = gr.Dropdown( ["Spam", "Audio Quality", "Dialect Mismatch", "Other"], value="Audio Quality", label="Reject Reason", ) reject_custom = gr.Textbox(label="Custom Reason") reject_btn = gr.Button("Reject Selected", variant="stop") with gr.Row(): undo_btn = gr.Button("Undo Last Approval/Rejection", variant="secondary") clear_btn = gr.Button("Sweep All Pending", variant="secondary") pending_status = gr.Textbox(label="Audit Log", interactive=False) with gr.Tab("PureChain History"): with gr.Row(): history_start = gr.Textbox(value="2020-01-01", label="Start Date") history_end = gr.Textbox(value=today, label="End Date") history_contracts = gr.CheckboxGroup( ["PureIUUY", "PureConvo", "PureVersation", "PureBi (Jun 11)", "PureBi (Jun 12)", "PureBi (Jun 13)", "PureBi"], value=["PureBi"], label="Contract Filter", ) history_refresh = gr.Button("Refresh History", variant="primary") history_df = gr.Dataframe( value=_empty_df(["Timestamp", "Utterance", "Dialect", "Data_Origin", "Data_Approved", "Block", "TX Hash"]), label="PureChain history", interactive=False, wrap=False, ) with gr.Tab("Rejected Entries Audit"): rejected_refresh = gr.Button("Refresh Rejected Entries", variant="primary") rejected_df = gr.Dataframe( value=_empty_df(["Utterance", "Dialect", "Rejection_Reason", "Rejector"]), label="Rejected entries", interactive=False, wrap=False, ) with gr.Tab("Bug Reports & Feedback"): with gr.Row(): feedback_operator = gr.Textbox(label="Operator ID") feedback_image = gr.File(label="Optional screenshot/image", type="filepath") feedback_text = gr.Textbox(label="Bug report or feedback", lines=4) with gr.Row(): feedback_submit = gr.Button("Submit Feedback", variant="primary") feedback_refresh = gr.Button("Refresh Feedback") feedback_status = gr.Textbox(label="Feedback Status", interactive=False) feedback_df = gr.Dataframe( value=_empty_df(["Timestamp", "Operator_ID", "Feedback_Text", "Image_Reference"]), label="System feedback log", interactive=False, wrap=False, ) pending_refresh.click(refresh_pending, [pending_language, pending_dialect, admin_review_key], pending_df) pending_df.select( select_pending_row, pending_df, [timestamp, original_utt, edit_utt, edit_lang, edit_dialect, edit_clar, edit_tone, audio_link], ) approve_btn.click( approve_pending, [timestamp, original_utt, edit_utt, edit_lang, edit_dialect, edit_clar, edit_tone, audio_override, admin_review_key, pending_language, pending_dialect], [pending_status, pending_df], ) reject_btn.click( reject_pending, [timestamp, original_utt, reject_reason, reject_custom, admin_review_key, pending_language, pending_dialect], [pending_status, pending_df], ) undo_btn.click(undo_last_admin_action, [admin_review_key, pending_language, pending_dialect], [pending_status, pending_df]) clear_btn.click(clear_pending, [admin_review_key, pending_language, pending_dialect], [pending_status, pending_df]) history_refresh.click(refresh_history, [history_start, history_end, history_contracts, admin_review_key], history_df) rejected_refresh.click(refresh_rejected, [admin_review_key], rejected_df) feedback_refresh.click(refresh_feedback, [admin_review_key], feedback_df) feedback_submit.click(submit_feedback, [feedback_operator, feedback_text, feedback_image, admin_review_key], [feedback_status, feedback_df]) if __name__ == "__main__": demo.launch()