Spaces:
Paused
Paused
| import random | |
| import datetime | |
| import gradio as gr | |
| from utils.filesys_utils import json_load | |
| from utils.common import list_completed_keys, upload_label | |
| ERROR_CATEGORIES = [ | |
| "λμκ΅°(μ½νΈνΈ) ν΄μ μ€λ₯", | |
| "μ§ν/κ³μ°μ ν΄μ μ€λ₯", | |
| "SQL ꡬ문/λ‘μ§ μ€λ₯", | |
| "κ²°κ³Όβμ€λͺ λΆμΌμΉ", | |
| "κΈ°ν", | |
| ] | |
| MAX_TURNS = 15 # actual max across the dataset is 13; a little headroom | |
| SESSIONS = json_load("data/sessions.json") | |
| SESSION_BY_KEY = {f"{s['pid']}_{s['sid']}": s for s in SESSIONS} | |
| # In-memory only, shared across all concurrent users of this single process. | |
| # Best-effort de-duplication of who's currently working on what; the durable | |
| # "is this session actually done" truth lives in the GitHub labels/ dir. | |
| CLAIMED: set = set() | |
| def render_dialogue_md(sess: dict) -> str: | |
| role_label = {"user": "π§ μ¬μ©μ", "assistant": "π€ μμ΄μ νΈ"} | |
| judgable_set = set(sess["judgable_turns"]) | |
| lines = [f"### μ°Έκ°μ `{sess['pid']}` / μΈμ `{sess['sid']}` (μ λ΅: {sess['strategy']})", ""] | |
| for i, t in enumerate(sess["dialogue"]): | |
| marker = " **β¬ λΌλ²¨λ§ λμ (μλμμ νλ¨)**" if i in judgable_set else "" | |
| lines.append(f"**#{i} [{t['type']}] {role_label[t['role']]}**{marker}") | |
| lines.append(t["content"]) | |
| lines.append("") | |
| return "\n".join(lines) | |
| def render_turn_detail_md(sess: dict, idx: int) -> str: | |
| t = sess["dialogue"][idx] | |
| lines = [f"#### νλ¨ λμ: ν΄ #{idx} ({t['type']})"] | |
| for j, s in enumerate(t.get("sql", [])): | |
| lines.append(f"**쿼리 {j + 1}:**") | |
| lines.append(f"```sql\n{s['query']}\n```") | |
| lines.append(f"**μ€ν κ²°κ³Ό:** `{s['result']}`") | |
| return "\n".join(lines) | |
| def _reset_turn_updates(): | |
| """One (visible=False, empty text, cleared radio, cleared checkboxes, | |
| cleared textbox) group per pre-allocated turn slot.""" | |
| updates = [] | |
| for _ in range(MAX_TURNS): | |
| updates += [gr.update(visible=False), "", gr.update(value=None), gr.update(value=[]), gr.update(value="")] | |
| return updates | |
| def get_new_session(): | |
| completed = list_completed_keys() | |
| available = [k for k in SESSION_BY_KEY if k not in completed and k not in CLAIMED] | |
| if not available: | |
| return ( | |
| [None, ""] | |
| + _reset_turn_updates() | |
| + [gr.update(visible=False), "π λͺ¨λ μΈμ μ΄ λΌλ²¨λ§λμμ΅λλ€! κ°μ¬ν©λλ€."] | |
| ) | |
| key = random.choice(available) | |
| CLAIMED.add(key) | |
| sess = SESSION_BY_KEY[key] | |
| judgable = sess["judgable_turns"] | |
| updates = [] | |
| for i in range(MAX_TURNS): | |
| if i < len(judgable): | |
| updates += [ | |
| gr.update(visible=True), | |
| render_turn_detail_md(sess, judgable[i]), | |
| gr.update(value=None), | |
| gr.update(value=[]), | |
| gr.update(value=""), | |
| ] | |
| else: | |
| updates += [gr.update(visible=False), "", gr.update(value=None), gr.update(value=[]), gr.update(value="")] | |
| status = f"μΈμ `{key}` λ°°μ λ¨ -- {len(judgable)}κ° ν΄μ λΌλ²¨λ§ν΄μ£ΌμΈμ." | |
| return [key, render_dialogue_md(sess)] + updates + [gr.update(visible=True), status] | |
| def submit_labels(key, *flat): | |
| # session_key_state is a gr.State -- it needs its actual (unchanged) value | |
| # passed through, not a bare gr.update(), which is only meaningful for | |
| # ordinary display/interactive components. | |
| def unchanged(msg): | |
| return [key, gr.update()] + [gr.update()] * (MAX_TURNS * 5) + [gr.update(), msg] | |
| if not key: | |
| return unchanged("λ¨Όμ 'μ μΈμ λ°κΈ°'λ₯Ό λλ¬μ£ΌμΈμ.") | |
| sess = SESSION_BY_KEY.get(key) | |
| if sess is None: | |
| return unchanged("μΈμ μ 보λ₯Ό μ°Ύμ μ μμ΅λλ€.") | |
| judgable = sess["judgable_turns"] | |
| n = len(judgable) | |
| verdicts = list(flat[0::3])[:n] | |
| cats_list = list(flat[1::3])[:n] | |
| reasons = list(flat[2::3])[:n] | |
| missing = [i + 1 for i, v in enumerate(verdicts) if not v] | |
| if missing: | |
| msg = f"β μμ§ νλ¨νμ§ μμ νλͺ©μ΄ μμ΅λλ€: #{', '.join(map(str, missing))}. λͺ¨λ 체ν¬ν΄μ£ΌμΈμ." | |
| return unchanged(msg) | |
| turn_labels = [ | |
| {"turn_index": idx, "verdict": v, "error_categories": c or [], "reason": r or ""} | |
| for idx, v, c, r in zip(judgable, verdicts, cats_list, reasons) | |
| ] | |
| payload = { | |
| "pid": sess["pid"], | |
| "sid": sess["sid"], | |
| "strategy": sess.get("strategy"), | |
| "source": sess.get("source"), | |
| "labeled_at": datetime.datetime.now().isoformat(), | |
| "turns": turn_labels, | |
| } | |
| ok, msg = upload_label(key, payload) | |
| if not ok: | |
| return unchanged(msg) | |
| CLAIMED.discard(key) | |
| # auto-advance to the next session on success | |
| next_state = get_new_session() | |
| next_state[-1] = f"{msg} λ€μ μΈμ μ λ°°μ νμ΅λλ€.\n\n{next_state[-1]}" | |
| return next_state | |
| css = """ | |
| .dialog-box { | |
| max-height: 500px; | |
| overflow-y: auto; | |
| border: 1px solid var(--border-color-primary); | |
| border-radius: 8px; | |
| padding: 12px; | |
| } | |
| """ | |
| with gr.Blocks(title="SQL Result Evaluation", css=css) as demo: | |
| gr.Markdown("# π©Ί SQL κ²°κ³Ό μ ν©μ± λΌλ²¨λ§") | |
| gr.Markdown( | |
| "μλ μ 체 λνλ₯Ό λκΉμ§ μ½κ³ , **'λΌλ²¨λ§ λμ'**μΌλ‘ νμλ κ° μμ΄μ νΈ μλ΅μ΄ " | |
| "μ€μ λ‘ μ€νλ SQLκ³Ό κ·Έ κ²°κ³Όλ₯Ό λ°νμΌλ‘ μ¬μ©μμ μ΅μ’ μλ" | |
| "(μ€κ°μ λͺ νν(clarification)κ° μμλ€λ©΄ κ·Έκ²κΉμ§ λ°μν μλ)μ λ§λ λ΅μ νλμ§ νλ¨ν΄μ£ΌμΈμ." | |
| ) | |
| gr.Markdown( | |
| "* ν μΈμ μλ λΌλ²¨λ§ λμμ΄ μ¬λ¬ κ° μμ μ μμ΅λλ€ -- μΈμ μ λͺ¨λ λμμ μ±μμΌ μ μΆλ©λλ€.\n" | |
| "* μ μΆνλ©΄ κ·Έ μΈμ μ μλ£ μ²λ¦¬λμ΄ λ€λ₯Έ μ¬λμκ² λ€μ λ°°μ λμ§ μμ΅λλ€.\n" | |
| "* 'νλ¦Ό'μ μ νν κ²½μ° μμΈ μΉ΄ν κ³ λ¦¬λ₯Ό 체ν¬νκ³ , κ°λ₯νλ©΄ μμ μμ λ‘ μ΄μ λ λ¨κ²¨μ£ΌμΈμ." | |
| ) | |
| session_key_state = gr.State(None) | |
| btn_new = gr.Button("π² μ μΈμ λ°κΈ°") | |
| status_msg = gr.Markdown("") | |
| dialogue_md = gr.Markdown(elem_classes="dialog-box") | |
| turn_groups, detail_mds, verdict_radios, category_checks, reason_boxes = [], [], [], [], [] | |
| for i in range(MAX_TURNS): | |
| with gr.Group(visible=False) as grp: | |
| detail = gr.Markdown() | |
| verdict = gr.Radio(["λ§μ", "νλ¦Ό"], label=f"νλ¨ #{i + 1}: μ΄ μλ΅μ μ¬μ©μμ μ΅μ’ μλμ λ§λμ?") | |
| cats = gr.CheckboxGroup(ERROR_CATEGORIES, label="μ€λ₯ μ ν (νλ Έμ λλ§ ν΄λΉνλ νλͺ© 체ν¬)") | |
| reason = gr.Textbox(label="μμ μμ μ΄μ ", lines=2) | |
| turn_groups.append(grp) | |
| detail_mds.append(detail) | |
| verdict_radios.append(verdict) | |
| category_checks.append(cats) | |
| reason_boxes.append(reason) | |
| with gr.Row(visible=False) as submit_row: | |
| submit_btn = gr.Button("π€ μ μΆνκΈ°") | |
| all_outputs = [session_key_state, dialogue_md] | |
| for grp, detail, verdict, cats, reason in zip(turn_groups, detail_mds, verdict_radios, category_checks, reason_boxes): | |
| all_outputs += [grp, detail, verdict, cats, reason] | |
| all_outputs += [submit_row, status_msg] | |
| btn_new.click(fn=get_new_session, inputs=[], outputs=all_outputs) | |
| submit_inputs = [session_key_state] | |
| for verdict, cats, reason in zip(verdict_radios, category_checks, reason_boxes): | |
| submit_inputs += [verdict, cats, reason] | |
| submit_btn.click(fn=submit_labels, inputs=submit_inputs, outputs=all_outputs) | |
| if __name__ == "__main__": | |
| demo.launch() | |