Spaces:
Paused
Paused
File size: 7,665 Bytes
7b45c3b c28406d 7b45c3b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 | 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()
|