Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -29,7 +29,8 @@ theme_css = """
|
|
| 29 |
}
|
| 30 |
|
| 31 |
/* Base */
|
| 32 |
-
body{ background:var(--bg); color:var(--text); }
|
|
|
|
| 33 |
|
| 34 |
/* Two-column layout */
|
| 35 |
.app-row { display:flex; align-items:flex-start; gap:16px; } /* was 24px */
|
|
@@ -53,6 +54,18 @@ body{ background:var(--bg); color:var(--text); }
|
|
| 53 |
}
|
| 54 |
.rowbtn:hover{ background:#f7fbff; border-color:#c3e8fb; }
|
| 55 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
/* Neighbor chips (smaller) */
|
| 57 |
.badge{
|
| 58 |
display:inline-block; padding:2px 6px; /* was 2px 8px */
|
|
@@ -241,7 +254,7 @@ def AutoPredictWatcher():
|
|
| 241 |
class HoverList(anywidget.AnyWidget):
|
| 242 |
"""
|
| 243 |
Renders the prediction rows in the browser and streams hover/click events
|
| 244 |
-
back to Python via synced traitlets.
|
| 245 |
"""
|
| 246 |
_esm = """
|
| 247 |
export function render({ model, el }) {
|
|
@@ -252,14 +265,20 @@ class HoverList(anywidget.AnyWidget):
|
|
| 252 |
wrap.style.display = 'flex';
|
| 253 |
wrap.style.flexDirection = 'column';
|
| 254 |
|
| 255 |
-
items.forEach((
|
|
|
|
|
|
|
| 256 |
const btn = document.createElement('button');
|
| 257 |
-
btn.textContent = label;
|
| 258 |
btn.className = 'rowbtn';
|
| 259 |
btn.setAttribute('type', 'button');
|
| 260 |
btn.setAttribute('role', 'button');
|
| 261 |
btn.setAttribute('tabindex', '0');
|
| 262 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 263 |
const preview = () => {
|
| 264 |
model.set('hovered_id', tid);
|
| 265 |
model.save_changes();
|
|
@@ -269,6 +288,7 @@ class HoverList(anywidget.AnyWidget):
|
|
| 269 |
btn.addEventListener('mousemove', preview);
|
| 270 |
btn.addEventListener('focus', preview);
|
| 271 |
|
|
|
|
| 272 |
btn.addEventListener('click', () => {
|
| 273 |
model.set('clicked_id', tid);
|
| 274 |
model.save_changes();
|
|
@@ -284,11 +304,10 @@ class HoverList(anywidget.AnyWidget):
|
|
| 284 |
model.on('change:items', renderList);
|
| 285 |
}
|
| 286 |
"""
|
| 287 |
-
items = t.List(trait=t.Dict()).tag(sync=True) # [{tid:int, label
|
| 288 |
hovered_id = t.Int(allow_none=True).tag(sync=True)
|
| 289 |
clicked_id = t.Int(allow_none=True).tag(sync=True)
|
| 290 |
|
| 291 |
-
|
| 292 |
# ---------- Predictions list (uses HoverList) ----------
|
| 293 |
@solara.component
|
| 294 |
def PredictionsList():
|
|
@@ -336,7 +355,7 @@ def PredictionsList():
|
|
| 336 |
def Page():
|
| 337 |
solara.Style(theme_css)
|
| 338 |
|
| 339 |
-
with solara.Column(margin=
|
| 340 |
solara.Markdown("# Next-Token Predictor + Semantic Neighborhood")
|
| 341 |
solara.Markdown(
|
| 342 |
"Type text to see AI's top predictions for the next token. "
|
|
|
|
| 29 |
}
|
| 30 |
|
| 31 |
/* Base */
|
| 32 |
+
body{ background:var(--bg); color:var(--text); margin:0;}
|
| 33 |
+
h1{ margin:6px 0 8px; }
|
| 34 |
|
| 35 |
/* Two-column layout */
|
| 36 |
.app-row { display:flex; align-items:flex-start; gap:16px; } /* was 24px */
|
|
|
|
| 54 |
}
|
| 55 |
.rowbtn:hover{ background:#f7fbff; border-color:#c3e8fb; }
|
| 56 |
|
| 57 |
+
/* New: 4-column grid inside each row button */
|
| 58 |
+
.rowbtn-grid{
|
| 59 |
+
display:grid;
|
| 60 |
+
grid-template-columns: 28px 72px 72px 1fr; /* # | probs | tokenID | token */
|
| 61 |
+
column-gap:8px;
|
| 62 |
+
align-items:center;
|
| 63 |
+
width:100%;
|
| 64 |
+
font-family: var(--mono);
|
| 65 |
+
font-size:13px;
|
| 66 |
+
line-height:1.15;
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
/* Neighbor chips (smaller) */
|
| 70 |
.badge{
|
| 71 |
display:inline-block; padding:2px 6px; /* was 2px 8px */
|
|
|
|
| 254 |
class HoverList(anywidget.AnyWidget):
|
| 255 |
"""
|
| 256 |
Renders the prediction rows in the browser and streams hover/click events
|
| 257 |
+
back to Python via synced traitlets. Supports HTML row labels via `label_html`.
|
| 258 |
"""
|
| 259 |
_esm = """
|
| 260 |
export function render({ model, el }) {
|
|
|
|
| 265 |
wrap.style.display = 'flex';
|
| 266 |
wrap.style.flexDirection = 'column';
|
| 267 |
|
| 268 |
+
items.forEach((item) => {
|
| 269 |
+
const { tid, label, label_html } = item;
|
| 270 |
+
|
| 271 |
const btn = document.createElement('button');
|
|
|
|
| 272 |
btn.className = 'rowbtn';
|
| 273 |
btn.setAttribute('type', 'button');
|
| 274 |
btn.setAttribute('role', 'button');
|
| 275 |
btn.setAttribute('tabindex', '0');
|
| 276 |
|
| 277 |
+
// Prefer HTML layout if provided; fall back to plain text
|
| 278 |
+
if (label_html) { btn.innerHTML = label_html; }
|
| 279 |
+
else { btn.textContent = label || ""; }
|
| 280 |
+
|
| 281 |
+
// Hover → preview (bind several events for reliability)
|
| 282 |
const preview = () => {
|
| 283 |
model.set('hovered_id', tid);
|
| 284 |
model.save_changes();
|
|
|
|
| 288 |
btn.addEventListener('mousemove', preview);
|
| 289 |
btn.addEventListener('focus', preview);
|
| 290 |
|
| 291 |
+
// Click → append
|
| 292 |
btn.addEventListener('click', () => {
|
| 293 |
model.set('clicked_id', tid);
|
| 294 |
model.save_changes();
|
|
|
|
| 304 |
model.on('change:items', renderList);
|
| 305 |
}
|
| 306 |
"""
|
| 307 |
+
items = t.List(trait=t.Dict()).tag(sync=True) # [{tid:int, label?:str, label_html?:str}, ...]
|
| 308 |
hovered_id = t.Int(allow_none=True).tag(sync=True)
|
| 309 |
clicked_id = t.Int(allow_none=True).tag(sync=True)
|
| 310 |
|
|
|
|
| 311 |
# ---------- Predictions list (uses HoverList) ----------
|
| 312 |
@solara.component
|
| 313 |
def PredictionsList():
|
|
|
|
| 355 |
def Page():
|
| 356 |
solara.Style(theme_css)
|
| 357 |
|
| 358 |
+
with solara.Column(margin=8, gap="10px"):
|
| 359 |
solara.Markdown("# Next-Token Predictor + Semantic Neighborhood")
|
| 360 |
solara.Markdown(
|
| 361 |
"Type text to see AI's top predictions for the next token. "
|