PureKITchat / app.py
GitHub Actions
🚀 Automated sync from GitHub
2b2aa51
Raw
History Blame Contribute Delete
12.9 kB
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()