Spaces:
Running
Running
Food Desert commited on
Commit ·
610c9e8
1
Parent(s): ddf8c33
Restore hover tooltips with robust row-index mapping
Browse files
app.py
CHANGED
|
@@ -72,6 +72,41 @@ def _choice_label_with_source_meta(tag: str, *, origin: str, preselected: bool)
|
|
| 72 |
return _display_tag_text(tag)
|
| 73 |
|
| 74 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
def _selection_source_rank(origin: str) -> int:
|
| 76 |
o = _normalize_selection_origin(origin)
|
| 77 |
if o == "structural":
|
|
@@ -562,10 +597,23 @@ def _build_display_audit_line(
|
|
| 562 |
}
|
| 563 |
for tag, rec in sorted(info_by_tag.items())
|
| 564 |
],
|
| 565 |
-
}
|
| 566 |
return "Display Tag Audit: " + json.dumps(payload, ensure_ascii=True)
|
| 567 |
|
| 568 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 569 |
def _build_row_component_updates(
|
| 570 |
row_defs: List[Dict[str, Any]],
|
| 571 |
selected_tags: List[str],
|
|
@@ -713,9 +761,11 @@ def _build_ui_payload(
|
|
| 713 |
continue
|
| 714 |
selected_ui_seen.add(t)
|
| 715 |
selected_ui.append(t)
|
|
|
|
| 716 |
return [
|
| 717 |
console_text,
|
| 718 |
gr.update(visible=bool(row_defs)),
|
|
|
|
| 719 |
prompt_text,
|
| 720 |
selected_ui,
|
| 721 |
False,
|
|
@@ -736,6 +786,7 @@ def _prepare_run_ui() -> List[Any]:
|
|
| 736 |
return [
|
| 737 |
"Running...",
|
| 738 |
gr.skip(),
|
|
|
|
| 739 |
"Running... usually completes in about 20 seconds.",
|
| 740 |
[],
|
| 741 |
False,
|
|
@@ -747,6 +798,18 @@ def _prepare_run_ui() -> List[Any]:
|
|
| 747 |
]
|
| 748 |
|
| 749 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 750 |
def _rebuild_rows_from_selected(
|
| 751 |
selected_tags_state: List[str],
|
| 752 |
row_defs_state: List[Dict[str, Any]],
|
|
@@ -820,9 +883,11 @@ def _rebuild_rows_from_selected(
|
|
| 820 |
selected_tags=selected_active,
|
| 821 |
max_rows=display_max_rows_default,
|
| 822 |
)
|
|
|
|
| 823 |
|
| 824 |
return [
|
| 825 |
gr.update(visible=bool(toggle_rows)),
|
|
|
|
| 826 |
prompt_text,
|
| 827 |
sorted(selected_active),
|
| 828 |
False,
|
|
@@ -1252,10 +1317,67 @@ css = """
|
|
| 1252 |
.suggested-prompt-card {
|
| 1253 |
margin-top: 10px !important;
|
| 1254 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1255 |
"""
|
| 1256 |
|
| 1257 |
client_js = """
|
| 1258 |
-
() => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1259 |
"""
|
| 1260 |
|
| 1261 |
|
|
@@ -1791,9 +1913,10 @@ with gr.Blocks(css=css, js=client_js) as app:
|
|
| 1791 |
)
|
| 1792 |
else:
|
| 1793 |
mascot_img = gr.Markdown("`(mascot image unavailable)`")
|
| 1794 |
-
submit_button = gr.Button("Run", variant="primary")
|
| 1795 |
gr.Markdown("Typical runtime: up to ~20 seconds.", elem_classes=["run-hint"])
|
| 1796 |
-
|
|
|
|
| 1797 |
selected_tags_state = gr.State([])
|
| 1798 |
rows_dirty_state = gr.State(False)
|
| 1799 |
row_defs_state = gr.State([])
|
|
@@ -1874,10 +1997,19 @@ with gr.Blocks(css=css, js=client_js) as app:
|
|
| 1874 |
interactive=False,
|
| 1875 |
placeholder="Progress logs will appear here."
|
| 1876 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1877 |
|
| 1878 |
run_outputs = [
|
| 1879 |
console,
|
| 1880 |
toggle_instruction,
|
|
|
|
| 1881 |
suggested_prompt,
|
| 1882 |
selected_tags_state,
|
| 1883 |
rows_dirty_state,
|
|
@@ -1888,7 +2020,21 @@ with gr.Blocks(css=css, js=client_js) as app:
|
|
| 1888 |
*row_checkboxes,
|
| 1889 |
]
|
| 1890 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1891 |
submit_button.click(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1892 |
_prepare_run_ui,
|
| 1893 |
inputs=[],
|
| 1894 |
outputs=run_outputs,
|
|
@@ -1901,6 +2047,12 @@ with gr.Blocks(css=css, js=client_js) as app:
|
|
| 1901 |
)
|
| 1902 |
|
| 1903 |
image_tags.submit(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1904 |
_prepare_run_ui,
|
| 1905 |
inputs=[],
|
| 1906 |
outputs=run_outputs,
|
|
@@ -1934,6 +2086,7 @@ with gr.Blocks(css=css, js=client_js) as app:
|
|
| 1934 |
inputs=[selected_tags_state, row_defs_state, row_values_state, display_top_groups, display_top_tags_per_group, display_rank_top_k],
|
| 1935 |
outputs=[
|
| 1936 |
toggle_instruction,
|
|
|
|
| 1937 |
suggested_prompt,
|
| 1938 |
selected_tags_state,
|
| 1939 |
rows_dirty_state,
|
|
|
|
| 72 |
return _display_tag_text(tag)
|
| 73 |
|
| 74 |
|
| 75 |
+
@lru_cache(maxsize=1)
|
| 76 |
+
def _load_tag_wiki_defs() -> Dict[str, str]:
|
| 77 |
+
p = Path("data/tag_wiki_defs.json")
|
| 78 |
+
if not p.exists():
|
| 79 |
+
return {}
|
| 80 |
+
try:
|
| 81 |
+
with p.open("r", encoding="utf-8") as f:
|
| 82 |
+
data = json.load(f)
|
| 83 |
+
out: Dict[str, str] = {}
|
| 84 |
+
if isinstance(data, dict):
|
| 85 |
+
for k, v in data.items():
|
| 86 |
+
tag = _norm_tag_for_lookup(str(k))
|
| 87 |
+
text = " ".join(str(v or "").split())
|
| 88 |
+
if tag and text:
|
| 89 |
+
out[tag] = text
|
| 90 |
+
return out
|
| 91 |
+
except Exception:
|
| 92 |
+
return {}
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
def _tooltip_text_for_tag(tag: str) -> str:
|
| 96 |
+
t = _norm_tag_for_lookup(tag)
|
| 97 |
+
parts: List[str] = []
|
| 98 |
+
try:
|
| 99 |
+
count = get_tag_counts().get(t)
|
| 100 |
+
except Exception:
|
| 101 |
+
count = None
|
| 102 |
+
if isinstance(count, int):
|
| 103 |
+
parts.append(f"Count: {count:,}")
|
| 104 |
+
d = _load_tag_wiki_defs().get(t, "")
|
| 105 |
+
if d:
|
| 106 |
+
parts.append(d)
|
| 107 |
+
return "\n".join(parts).strip()
|
| 108 |
+
|
| 109 |
+
|
| 110 |
def _selection_source_rank(origin: str) -> int:
|
| 111 |
o = _normalize_selection_origin(origin)
|
| 112 |
if o == "structural":
|
|
|
|
| 597 |
}
|
| 598 |
for tag, rec in sorted(info_by_tag.items())
|
| 599 |
],
|
| 600 |
+
}
|
| 601 |
return "Display Tag Audit: " + json.dumps(payload, ensure_ascii=True)
|
| 602 |
|
| 603 |
|
| 604 |
+
def _build_tooltip_payload(row_defs: List[Dict[str, Any]], max_rows: int) -> str:
|
| 605 |
+
row_defs_ui = (row_defs or [])[: max(0, int(max_rows))]
|
| 606 |
+
tips: Dict[str, str] = {}
|
| 607 |
+
rows: List[List[str]] = []
|
| 608 |
+
for row in row_defs_ui:
|
| 609 |
+
tags = _dedupe_norm_tags(row.get("tags", []) if isinstance(row, dict) else [])
|
| 610 |
+
rows.append(tags)
|
| 611 |
+
for t in tags:
|
| 612 |
+
if t not in tips:
|
| 613 |
+
tips[t] = _tooltip_text_for_tag(t)
|
| 614 |
+
return json.dumps({"rows": rows, "tips": tips}, ensure_ascii=True)
|
| 615 |
+
|
| 616 |
+
|
| 617 |
def _build_row_component_updates(
|
| 618 |
row_defs: List[Dict[str, Any]],
|
| 619 |
selected_tags: List[str],
|
|
|
|
| 761 |
continue
|
| 762 |
selected_ui_seen.add(t)
|
| 763 |
selected_ui.append(t)
|
| 764 |
+
tooltip_payload = _build_tooltip_payload(row_defs, display_max_rows_default)
|
| 765 |
return [
|
| 766 |
console_text,
|
| 767 |
gr.update(visible=bool(row_defs)),
|
| 768 |
+
tooltip_payload,
|
| 769 |
prompt_text,
|
| 770 |
selected_ui,
|
| 771 |
False,
|
|
|
|
| 786 |
return [
|
| 787 |
"Running...",
|
| 788 |
gr.skip(),
|
| 789 |
+
"{}",
|
| 790 |
"Running... usually completes in about 20 seconds.",
|
| 791 |
[],
|
| 792 |
False,
|
|
|
|
| 798 |
]
|
| 799 |
|
| 800 |
|
| 801 |
+
def _update_run_button_visibility(prompt_text: str, last_run_prompt: str):
|
| 802 |
+
curr = (prompt_text or "").strip()
|
| 803 |
+
last = (last_run_prompt or "").strip()
|
| 804 |
+
can_run = bool(curr) and curr != last
|
| 805 |
+
return gr.update(visible=can_run, interactive=can_run)
|
| 806 |
+
|
| 807 |
+
|
| 808 |
+
def _mark_run_triggered(prompt_text: str):
|
| 809 |
+
curr = (prompt_text or "").strip()
|
| 810 |
+
return gr.update(visible=False, interactive=False), curr
|
| 811 |
+
|
| 812 |
+
|
| 813 |
def _rebuild_rows_from_selected(
|
| 814 |
selected_tags_state: List[str],
|
| 815 |
row_defs_state: List[Dict[str, Any]],
|
|
|
|
| 883 |
selected_tags=selected_active,
|
| 884 |
max_rows=display_max_rows_default,
|
| 885 |
)
|
| 886 |
+
tooltip_payload = _build_tooltip_payload(toggle_rows, display_max_rows_default)
|
| 887 |
|
| 888 |
return [
|
| 889 |
gr.update(visible=bool(toggle_rows)),
|
| 890 |
+
tooltip_payload,
|
| 891 |
prompt_text,
|
| 892 |
sorted(selected_active),
|
| 893 |
False,
|
|
|
|
| 1317 |
.suggested-prompt-card {
|
| 1318 |
margin-top: 10px !important;
|
| 1319 |
}
|
| 1320 |
+
|
| 1321 |
+
.psq-hidden {
|
| 1322 |
+
display: none !important;
|
| 1323 |
+
}
|
| 1324 |
"""
|
| 1325 |
|
| 1326 |
client_js = """
|
| 1327 |
+
() => {
|
| 1328 |
+
const readTooltipMap = () => {
|
| 1329 |
+
const el = document.querySelector("#psq-tooltip-map textarea, #psq-tooltip-map input");
|
| 1330 |
+
if (!el) return { rows: [], tips: {} };
|
| 1331 |
+
const raw = (el.value || "").trim();
|
| 1332 |
+
if (!raw) return { rows: [], tips: {} };
|
| 1333 |
+
try {
|
| 1334 |
+
const obj = JSON.parse(raw);
|
| 1335 |
+
if (!obj || typeof obj !== "object") return { rows: [], tips: {} };
|
| 1336 |
+
const rows = Array.isArray(obj.rows) ? obj.rows : [];
|
| 1337 |
+
const tips = (obj.tips && typeof obj.tips === "object") ? obj.tips : {};
|
| 1338 |
+
return { rows, tips };
|
| 1339 |
+
} catch (_) {
|
| 1340 |
+
return { rows: [], tips: {} };
|
| 1341 |
+
}
|
| 1342 |
+
};
|
| 1343 |
+
|
| 1344 |
+
const applyTooltips = () => {
|
| 1345 |
+
const payload = readTooltipMap();
|
| 1346 |
+
const rowTags = Array.isArray(payload.rows) ? payload.rows : [];
|
| 1347 |
+
const tipMap = (payload.tips && typeof payload.tips === "object") ? payload.tips : {};
|
| 1348 |
+
const rowEls = document.querySelectorAll(".lego-tags");
|
| 1349 |
+
rowEls.forEach((rowEl, rowIdx) => {
|
| 1350 |
+
const tags = Array.isArray(rowTags[rowIdx]) ? rowTags[rowIdx] : [];
|
| 1351 |
+
const labels = rowEl.querySelectorAll("label");
|
| 1352 |
+
labels.forEach((label, tagIdx) => {
|
| 1353 |
+
const span = label.querySelector("span");
|
| 1354 |
+
const tag = (tagIdx < tags.length) ? tags[tagIdx] : "";
|
| 1355 |
+
const tip = tag && Object.prototype.hasOwnProperty.call(tipMap, tag) ? (tipMap[tag] || "") : "";
|
| 1356 |
+
if (tip) {
|
| 1357 |
+
label.title = tip;
|
| 1358 |
+
if (span) span.title = tip;
|
| 1359 |
+
} else {
|
| 1360 |
+
label.removeAttribute("title");
|
| 1361 |
+
if (span) span.removeAttribute("title");
|
| 1362 |
+
}
|
| 1363 |
+
});
|
| 1364 |
+
});
|
| 1365 |
+
};
|
| 1366 |
+
|
| 1367 |
+
let scheduled = false;
|
| 1368 |
+
const scheduleApply = () => {
|
| 1369 |
+
if (scheduled) return;
|
| 1370 |
+
scheduled = true;
|
| 1371 |
+
requestAnimationFrame(() => {
|
| 1372 |
+
scheduled = false;
|
| 1373 |
+
applyTooltips();
|
| 1374 |
+
});
|
| 1375 |
+
};
|
| 1376 |
+
|
| 1377 |
+
scheduleApply();
|
| 1378 |
+
const observer = new MutationObserver(() => scheduleApply());
|
| 1379 |
+
observer.observe(document.body, { childList: true, subtree: true });
|
| 1380 |
+
}
|
| 1381 |
"""
|
| 1382 |
|
| 1383 |
|
|
|
|
| 1913 |
)
|
| 1914 |
else:
|
| 1915 |
mascot_img = gr.Markdown("`(mascot image unavailable)`")
|
| 1916 |
+
submit_button = gr.Button("Run", variant="primary", visible=False, interactive=False)
|
| 1917 |
gr.Markdown("Typical runtime: up to ~20 seconds.", elem_classes=["run-hint"])
|
| 1918 |
+
|
| 1919 |
+
last_run_prompt_state = gr.State("")
|
| 1920 |
selected_tags_state = gr.State([])
|
| 1921 |
rows_dirty_state = gr.State(False)
|
| 1922 |
row_defs_state = gr.State([])
|
|
|
|
| 1997 |
interactive=False,
|
| 1998 |
placeholder="Progress logs will appear here."
|
| 1999 |
)
|
| 2000 |
+
tooltip_map_payload = gr.Textbox(
|
| 2001 |
+
value="{}",
|
| 2002 |
+
visible=True,
|
| 2003 |
+
interactive=False,
|
| 2004 |
+
container=False,
|
| 2005 |
+
elem_id="psq-tooltip-map",
|
| 2006 |
+
elem_classes=["psq-hidden"],
|
| 2007 |
+
)
|
| 2008 |
|
| 2009 |
run_outputs = [
|
| 2010 |
console,
|
| 2011 |
toggle_instruction,
|
| 2012 |
+
tooltip_map_payload,
|
| 2013 |
suggested_prompt,
|
| 2014 |
selected_tags_state,
|
| 2015 |
rows_dirty_state,
|
|
|
|
| 2020 |
*row_checkboxes,
|
| 2021 |
]
|
| 2022 |
|
| 2023 |
+
image_tags.change(
|
| 2024 |
+
_update_run_button_visibility,
|
| 2025 |
+
inputs=[image_tags, last_run_prompt_state],
|
| 2026 |
+
outputs=[submit_button],
|
| 2027 |
+
queue=False,
|
| 2028 |
+
show_progress="hidden",
|
| 2029 |
+
)
|
| 2030 |
+
|
| 2031 |
submit_button.click(
|
| 2032 |
+
_mark_run_triggered,
|
| 2033 |
+
inputs=[image_tags],
|
| 2034 |
+
outputs=[submit_button, last_run_prompt_state],
|
| 2035 |
+
queue=False,
|
| 2036 |
+
show_progress="hidden",
|
| 2037 |
+
).then(
|
| 2038 |
_prepare_run_ui,
|
| 2039 |
inputs=[],
|
| 2040 |
outputs=run_outputs,
|
|
|
|
| 2047 |
)
|
| 2048 |
|
| 2049 |
image_tags.submit(
|
| 2050 |
+
_mark_run_triggered,
|
| 2051 |
+
inputs=[image_tags],
|
| 2052 |
+
outputs=[submit_button, last_run_prompt_state],
|
| 2053 |
+
queue=False,
|
| 2054 |
+
show_progress="hidden",
|
| 2055 |
+
).then(
|
| 2056 |
_prepare_run_ui,
|
| 2057 |
inputs=[],
|
| 2058 |
outputs=run_outputs,
|
|
|
|
| 2086 |
inputs=[selected_tags_state, row_defs_state, row_values_state, display_top_groups, display_top_tags_per_group, display_rank_top_k],
|
| 2087 |
outputs=[
|
| 2088 |
toggle_instruction,
|
| 2089 |
+
tooltip_map_payload,
|
| 2090 |
suggested_prompt,
|
| 2091 |
selected_tags_state,
|
| 2092 |
rows_dirty_state,
|