CodeChamp95 commited on
Commit
6389fcd
Β·
verified Β·
1 Parent(s): f2d554c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +97 -26
app.py CHANGED
@@ -633,59 +633,130 @@ def build_app():
633
  )
634
 
635
  def _rows_to_html(rows):
636
- """Convert agent row data β†’ (html_str, json_str) for the custom table."""
637
- if not rows:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
638
  html = "<p class='rt-empty'>No topics yet β€” run topic modelling first.</p>"
639
  return html, "[]"
640
 
641
- padded = []
642
- for r in rows:
643
- row = list(r) + [""] * max(0, 8 - len(r))
644
- padded.append(row[:8])
645
-
646
- json_data = json.dumps(padded)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
647
 
648
  rows_html = ""
649
- for i, row in enumerate(padded):
650
  num, label, evidence, sentences, papers, approve, rename, reasoning = row
651
  checked = "checked" if str(approve).lower() in ("true", "1", "yes", "βœ“") else ""
652
- # Escape for HTML attribute safety
653
- rename_esc = str(rename).replace('"', "&quot;")
654
- reason_esc = str(reasoning).replace("<", "&lt;").replace(">", "&gt;")
655
- evidence_esc = str(evidence).replace("<", "&lt;").replace(">", "&gt;")
656
- label_esc = str(label).replace("<", "&lt;").replace(">", "&gt;")
657
  rows_html += f"""
658
  <tr data-row="{i}">
659
- <td class="rt-col-num">{num}</td>
660
- <td class="rt-col-label">{label_esc}</td>
661
- <td class="rt-col-evid">{evidence_esc}</td>
662
- <td class="rt-col-sent">{sentences}</td>
663
- <td class="rt-col-paper">{papers}</td>
664
  <td class="rt-col-appr">
665
  <input type="checkbox" class="rt-check" {checked}
666
  onchange="rtUpdate({i},5,this.checked)">
667
  </td>
668
  <td class="rt-col-rename">
669
- <input type="text" class="rt-input" value="{rename_esc}"
670
- oninput="rtUpdate({i},6,this.value)" placeholder="new label…">
 
 
671
  </td>
672
  <td class="rt-col-reason">
673
  <textarea class="rt-textarea" rows="2"
674
- oninput="rtUpdate({i},7,this.value)" placeholder="notes…">{reason_esc}</textarea>
 
675
  </td>
676
  </tr>"""
677
 
 
 
 
678
  html = f"""<div id="review-table-wrap">
679
  <script>
680
  (function(){{
 
681
  window._rtData = {json_data};
 
682
  window.rtUpdate = function(idx, col, val) {{
 
683
  window._rtData[idx][col] = val;
684
- var el = document.querySelector('#review-json-state textarea');
685
- if (!el) return;
686
- var setter = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype,'value').set;
 
 
 
 
 
 
 
 
687
  setter.call(el, JSON.stringify(window._rtData));
688
- el.dispatchEvent(new Event('input',{{bubbles:true}}));
689
  }};
690
  }})();
691
  </script>
 
633
  )
634
 
635
  def _rows_to_html(rows):
636
+ """Convert agent row data β†’ (html_str, json_str).
637
+ Accepts list-of-lists, list-of-dicts, list-of-tuples, or pd.DataFrame.
638
+ """
639
+ if rows is None:
640
+ rows = []
641
+
642
+ # ── Normalise to list-of-lists in TABLE_COLS order ──────────────
643
+ # Alias map: agent may use slightly different key names
644
+ _ALIASES = {
645
+ "top evidence (truncated)": "Top Evidence",
646
+ "top evidence": "Top Evidence",
647
+ "topic label": "Topic Label",
648
+ "rename to": "Rename To",
649
+ "approve": "Approve",
650
+ "reasoning": "Reasoning",
651
+ "sentences": "Sentences",
652
+ "papers": "Papers",
653
+ "#": "#",
654
+ }
655
+
656
+ if isinstance(rows, pd.DataFrame):
657
+ # Normalise column names via alias map
658
+ rows.columns = [_ALIASES.get(c.lower(), c) for c in rows.columns]
659
+ for col in TABLE_COLS:
660
+ if col not in rows.columns:
661
+ rows[col] = ""
662
+ padded = rows[TABLE_COLS].fillna("").values.tolist()
663
+
664
+ elif rows and isinstance(rows[0], dict):
665
+ # Remap keys through alias table then extract in TABLE_COLS order
666
+ normalised = []
667
+ for r in rows:
668
+ remapped = {_ALIASES.get(k.lower(), k): v for k, v in r.items()}
669
+ normalised.append([remapped.get(col, "") for col in TABLE_COLS])
670
+ padded = normalised
671
+
672
+ else:
673
+ # List of lists / tuples β€” pad / truncate to exactly 8 columns
674
+ padded = []
675
+ for r in rows:
676
+ row = list(r) + [""] * max(0, 8 - len(list(r)))
677
+ padded.append(row[:8])
678
+
679
+ if not padded:
680
  html = "<p class='rt-empty'>No topics yet β€” run topic modelling first.</p>"
681
  return html, "[]"
682
 
683
+ # ── Serialise to JSON (drives JS state) ─────────────────────────
684
+ # Convert non-serialisable types (numpy bools, NaN, etc.) safely
685
+ def _safe(v):
686
+ if v is None or (isinstance(v, float) and v != v): # NaN check
687
+ return ""
688
+ try:
689
+ import numpy as np
690
+ if isinstance(v, (np.bool_, np.integer, np.floating)):
691
+ return v.item()
692
+ except ImportError:
693
+ pass
694
+ return v
695
+
696
+ safe_padded = [[_safe(c) for c in row] for row in padded]
697
+ json_data = json.dumps(safe_padded, ensure_ascii=False)
698
+
699
+ # ── Build HTML rows ──────────────────────────────────────────────
700
+ def _esc(v, attr=False):
701
+ s = str(v) if v is not None else ""
702
+ s = s.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
703
+ if attr:
704
+ s = s.replace('"', "&quot;").replace("'", "&#39;")
705
+ return s
706
 
707
  rows_html = ""
708
+ for i, row in enumerate(safe_padded):
709
  num, label, evidence, sentences, papers, approve, rename, reasoning = row
710
  checked = "checked" if str(approve).lower() in ("true", "1", "yes", "βœ“") else ""
 
 
 
 
 
711
  rows_html += f"""
712
  <tr data-row="{i}">
713
+ <td class="rt-col-num">{_esc(num)}</td>
714
+ <td class="rt-col-label">{_esc(label)}</td>
715
+ <td class="rt-col-evid">{_esc(evidence)}</td>
716
+ <td class="rt-col-sent">{_esc(sentences)}</td>
717
+ <td class="rt-col-paper">{_esc(papers)}</td>
718
  <td class="rt-col-appr">
719
  <input type="checkbox" class="rt-check" {checked}
720
  onchange="rtUpdate({i},5,this.checked)">
721
  </td>
722
  <td class="rt-col-rename">
723
+ <input type="text" class="rt-input"
724
+ value="{_esc(rename, attr=True)}"
725
+ oninput="rtUpdate({i},6,this.value)"
726
+ placeholder="new label…">
727
  </td>
728
  <td class="rt-col-reason">
729
  <textarea class="rt-textarea" rows="2"
730
+ oninput="rtUpdate({i},7,this.value)"
731
+ placeholder="notes…">{_esc(reasoning)}</textarea>
732
  </td>
733
  </tr>"""
734
 
735
+ # ── Assemble full HTML block ─────────────────────────────────────
736
+ # Use a unique suffix so re-renders don't collide with stale globals
737
+ uid = id(safe_padded)
738
  html = f"""<div id="review-table-wrap">
739
  <script>
740
  (function(){{
741
+ // Initialise or refresh the shared row-data store
742
  window._rtData = {json_data};
743
+
744
  window.rtUpdate = function(idx, col, val) {{
745
+ if (!window._rtData || !window._rtData[idx]) return;
746
  window._rtData[idx][col] = val;
747
+ // Push updated JSON into the hidden Gradio textbox
748
+ // Try both possible DOM locations Gradio uses across versions
749
+ var el = (
750
+ document.querySelector('#review-json-state textarea') ||
751
+ document.querySelector('[id*="review-json-state"] textarea') ||
752
+ document.querySelector('textarea[data-testid="textbox"]')
753
+ );
754
+ if (!el) {{ console.warn("rtUpdate: hidden textbox not found"); return; }}
755
+ var setter = Object.getOwnPropertyDescriptor(
756
+ window.HTMLTextAreaElement.prototype, 'value'
757
+ ).set;
758
  setter.call(el, JSON.stringify(window._rtData));
759
+ el.dispatchEvent(new Event('input', {{bubbles: true}}));
760
  }};
761
  }})();
762
  </script>