han-na commited on
Commit
3a0ff69
Β·
1 Parent(s): f783841

button fix

Browse files
Files changed (1) hide show
  1. app.py +112 -111
app.py CHANGED
@@ -55,13 +55,11 @@ html, body, [class*="css"],
55
  max-width: 960px !important;
56
  }
57
 
58
- /* Pull the first widget block up closer to the masthead divider */
59
  .block-container > div:first-child {
60
  margin-top: 0 !important;
61
  padding-top: 0 !important;
62
  }
63
 
64
- /* Text input β€” remove blue focus background */
65
  div[data-testid="stTextInput"] input,
66
  div[data-testid="stTextInput"] input:focus,
67
  div[data-testid="stTextInput"] input:active {
@@ -79,7 +77,6 @@ div[data-testid="stVerticalBlock"] > div:has(div[data-testid="stTextInput"]) {
79
  }
80
  #MainMenu, footer, header { visibility: hidden; }
81
 
82
- /* Smooth scroll β€” target Streamlit's actual scroll container */
83
  html, body, [data-testid="stAppViewContainer"], .main, .block-container,
84
  section[data-testid="stMain"], div[data-testid="stAppViewBlockContainer"] {
85
  scroll-behavior: smooth !important;
@@ -134,6 +131,7 @@ details.full-text-expander summary:hover { color: var(--gold); }
134
  transition: border-color 0.3s, box-shadow 0.3s;
135
  }
136
 
 
137
  div[data-testid="stButton"] button[kind="primary"] {
138
  background-color: var(--gold) !important;
139
  border: none !important;
@@ -148,6 +146,7 @@ div[data-testid="stButton"] button[kind="primary"]:hover {
148
  background-color: var(--sepia) !important;
149
  }
150
 
 
151
  div[data-testid="stButton"] button[kind="secondary"] {
152
  background: var(--tag-bg) !important;
153
  border: 1px solid var(--border) !important;
@@ -166,6 +165,57 @@ div[data-testid="stButton"] button[kind="secondary"]:hover {
166
  font-style: normal !important;
167
  }
168
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  .masthead {
170
  text-align: center;
171
  padding: 3.5rem 1rem 2rem;
@@ -230,7 +280,7 @@ div[data-testid="stButton"] button[kind="secondary"]:hover {
230
  .result-card {
231
  background: var(--card-bg); border: 1px solid var(--border);
232
  border-radius: 4px; padding: 1.4rem 1.6rem;
233
- margin-bottom: 1rem; scroll-margin-top: 80px;
234
  transition: border-color 0.3s, box-shadow 0.3s;
235
  }
236
  .result-card:hover { border-color: var(--gold); box-shadow: 0 4px 18px rgba(200,151,58,0.12); }
@@ -271,16 +321,10 @@ div[data-testid="stButton"] button[kind="secondary"]:hover {
271
  .no-results-icon { font-size:3rem; margin-bottom:1rem; }
272
  .no-results-title { font-family:'Playfair Display',serif; font-size:1.4rem; color:var(--ink); margin-bottom:0.5rem; }
273
 
274
- /* Align form columns to bottom so button sits flush with input */
275
  div[data-testid="stForm"] div[data-testid="stHorizontalBlock"] {
276
  align-items: flex-end !important;
277
  }
278
 
279
- /* Pagination buttons */
280
- div[data-testid="stButton"] button[kind="secondary"].pagination {
281
- border-radius: 4px !important;
282
- }
283
-
284
  .bpl-footer {
285
  text-align:center; padding:2.5rem 1rem 1rem;
286
  border-top:1px solid var(--border); margin-top:3rem;
@@ -288,40 +332,6 @@ div[data-testid="stButton"] button[kind="secondary"].pagination {
288
  }
289
  .bpl-footer strong { color: var(--sepia); }
290
 
291
- /* Thumbs up/down feedback buttons (per-result).
292
- - Empty state (kind=secondary): outlined icon, dark pill, muted color.
293
- - Filled state (kind=primary): gold background, filled icon, white.
294
- Material Symbols supports fill via font-variation-settings. */
295
- div[data-testid="stButton"] button:has(span[class*="material-symbols"]) {
296
- border-radius: 6px !important;
297
- font-style: normal !important;
298
- padding: 0.35rem 0.5rem !important;
299
- min-height: 0 !important;
300
- }
301
- div[data-testid="stButton"] button[kind="secondary"]:has(span[class*="material-symbols"]) {
302
- background: var(--tag-bg) !important;
303
- border: 1px solid var(--border) !important;
304
- color: var(--muted) !important;
305
- }
306
- div[data-testid="stButton"] button[kind="secondary"]:has(span[class*="material-symbols"]):hover {
307
- border-color: var(--gold) !important;
308
- color: var(--gold) !important;
309
- }
310
- div[data-testid="stButton"] button[kind="primary"]:has(span[class*="material-symbols"]) {
311
- background: var(--gold) !important;
312
- border: 1px solid var(--gold) !important;
313
- color: #fff !important;
314
- }
315
- div[data-testid="stButton"] button[kind="secondary"] span[class*="material-symbols"] {
316
- font-variation-settings: 'FILL' 0 !important;
317
- font-size: 1.15rem !important;
318
- }
319
- div[data-testid="stButton"] button[kind="primary"] span[class*="material-symbols"] {
320
- font-variation-settings: 'FILL' 1 !important;
321
- font-size: 1.15rem !important;
322
- }
323
-
324
- /* Hide Streamlit's built-in "Press Cmd+Enter to apply" hint on text inputs */
325
  [data-testid="InputInstructions"],
326
  [data-testid="stTextAreaInstructions"],
327
  [data-testid="stWidgetInstructions"],
@@ -329,18 +339,6 @@ div[data-testid="stTextArea"] small,
329
  div[data-testid="stTextInput"] small {
330
  display: none !important;
331
  }
332
-
333
- /* Feedback buttons β€” compact, inline feel */
334
- div[data-testid="stHorizontalBlock"] div[data-testid="stButton"] button {
335
- white-space: nowrap !important;
336
- width: auto !important;
337
- min-width: 0 !important;
338
- padding: 0.25rem 0.9rem !important;
339
- font-size: 0.75rem !important;
340
- border-radius: 20px !important;
341
- font-style: normal !important;
342
- overflow: hidden !important;
343
- }
344
  </style>
345
  """, unsafe_allow_html=True)
346
 
@@ -356,7 +354,6 @@ EXAMPLE_QUERIES = [
356
 
357
  # ── Helpers ───────────────────────────────────────────────────────────────────
358
  def linkify_citations(text: str, num_docs: int) -> str:
359
- """Use plain anchor hrefs β€” browser handles scroll natively, no JS needed."""
360
  def replace(match):
361
  n = int(match.group(1))
362
  if 1 <= n <= num_docs:
@@ -407,7 +404,6 @@ def build_card_html(r: dict, i: int) -> str:
407
  'border-radius:4px;margin-bottom:0.8rem;" />'
408
  if r.get("thumbnail", "").startswith("https://") else ""
409
  )
410
- # Full text expander β€” only when doc has more text than the snippet
411
  full_text = r.get("full_text", "")
412
  if full_text and len(full_text) > 300:
413
  expander = (
@@ -448,22 +444,20 @@ def build_card_html(r: dict, i: int) -> str:
448
  for k, v in [
449
  ("query", ""), ("results", None), ("searched", False),
450
  ("context", ""), ("latency_ms", 0), ("_last_ran", ""), ("page", 0),
451
- ("query_id", None), # Postgres query_logs.id of last run
452
- ("docs", []), # raw RetrievedDocument list (for refine)
453
- ("thumbs", {}), # {ark_id: "up"|"down"} for current results
454
- ("missing_text", ""), # last "missed the point" comment
455
- ("refined_with", []), # last set of follow-up queries shown
456
- ("_scroll_to_top", False), # set after refine succeeds, consumed below
457
  ]:
458
  if k not in st.session_state:
459
  st.session_state[k] = v
460
 
461
- # Per-browser-session UUID β€” anonymous, stable across reruns of this tab.
462
  if "session_id" not in st.session_state:
463
  st.session_state["session_id"] = str(uuid.uuid4())
464
 
465
 
466
-
467
  # ── Masthead ──────────────────────────────────────────────────────────────────
468
  st.markdown("""
469
  <div class="masthead">
@@ -508,7 +502,6 @@ for i, q in enumerate(EXAMPLE_QUERIES):
508
  pill_clicked = q
509
 
510
 
511
-
512
  # ── Determine active query ────────────────────────────────────────────────────
513
  if pill_clicked:
514
  st.session_state.query = pill_clicked
@@ -550,7 +543,6 @@ if st.session_state.searched and st.session_state.results is not None:
550
  st.markdown('<hr class="divider">', unsafe_allow_html=True)
551
 
552
  if results:
553
- # ── Refined-search banner (only when a refine just ran) ───────────
554
  if st.session_state["refined_with"]:
555
  chips = " Β· ".join(html.escape(q) for q in st.session_state["refined_with"])
556
  st.markdown(
@@ -559,7 +551,6 @@ if st.session_state.searched and st.session_state.results is not None:
559
  unsafe_allow_html=True,
560
  )
561
 
562
- # ── Scroll to top after a refinement (one-shot) ───────────────────
563
  if st.session_state["_scroll_to_top"]:
564
  st.session_state["_scroll_to_top"] = False
565
  components.html(
@@ -597,12 +588,6 @@ if st.session_state.searched and st.session_state.results is not None:
597
  unsafe_allow_html=True,
598
  )
599
 
600
- # ── Citation scroll ───────────────────────────────────────────────────
601
- # After a ?scroll_to=N reload, results re-render from session_state,
602
- # then this components.html block scrolls and highlights the target card.
603
-
604
-
605
- # ── Pagination ────────────────────────────────────────────────────
606
  PAGE_SIZE = 10
607
  total_pages = max(1, (len(results) + PAGE_SIZE - 1) // PAGE_SIZE)
608
  page = st.session_state["page"]
@@ -613,37 +598,56 @@ if st.session_state.searched and st.session_state.results is not None:
613
 
614
  page_docs = st.session_state.docs[start:end]
615
  for i, (r, doc) in enumerate(zip(page_results, page_docs), start=start + 1):
616
- st.markdown(build_card_html(r, i), unsafe_allow_html=True)
617
-
618
- # ── Feedback row (thumbs only) ────────────────────────────────
619
- current = st.session_state["thumbs"].get(doc.ark_id)
620
- fb_cols = st.columns([2, 3, 20])
621
- with fb_cols[0]:
622
- up_type = "primary" if current == "up" else "secondary"
623
- if st.button("βœ“ Helpful", key=f"up_{i}_{doc.ark_id}",
624
- type=up_type, help="Helpful result"):
625
- st.session_state["thumbs"][doc.ark_id] = "up"
626
- log_feedback(
627
- query_id = st.session_state["query_id"],
628
- ark_id = doc.ark_id,
629
- signal = "up",
630
- session_id = st.session_state["session_id"],
631
- raw_query = st.session_state["query"],
632
- )
633
- st.rerun()
634
- with fb_cols[1]:
635
- down_type = "primary" if current == "down" else "secondary"
636
- if st.button("βœ— Not relevant", key=f"down_{i}_{doc.ark_id}",
637
- type=down_type, help="Not what I wanted"):
638
- st.session_state["thumbs"][doc.ark_id] = "down"
639
- log_feedback(
640
- query_id = st.session_state["query_id"],
641
- ark_id = doc.ark_id,
642
- signal = "down",
643
- session_id = st.session_state["session_id"],
644
- raw_query = st.session_state["query"],
645
- )
646
- st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
647
 
648
  # ── Pagination controls ───────────────────────────────────────────────
649
  if total_pages > 1:
@@ -669,7 +673,7 @@ if st.session_state.searched and st.session_state.results is not None:
669
  st.session_state["page"] += 1
670
  st.rerun()
671
 
672
- # ── Human-in-the-loop: user-typed refinement ──────────────────────
673
  st.markdown('<hr class="divider">', unsafe_allow_html=True)
674
  st.markdown(
675
  '<div class="search-label">Didn\'t find any relevant results?</div>',
@@ -688,14 +692,11 @@ if st.session_state.searched and st.session_state.results is not None:
688
  placeholder="e.g. photographs of JFK as a senator in 1958, not newspaper clippings",
689
  label_visibility="collapsed",
690
  )
691
- if st.button("Refine search", key="refine_btn",
692
- use_container_width=True):
693
  user_text = st.session_state["missing_text"].strip()
694
  if not user_text:
695
  st.info("Type a refined query before clicking refine.")
696
  else:
697
- # Log as 'missing' feedback so the team can see what queries
698
- # the original retrieval was failing on.
699
  log_feedback(
700
  query_id = st.session_state["query_id"],
701
  ark_id = "",
 
55
  max-width: 960px !important;
56
  }
57
 
 
58
  .block-container > div:first-child {
59
  margin-top: 0 !important;
60
  padding-top: 0 !important;
61
  }
62
 
 
63
  div[data-testid="stTextInput"] input,
64
  div[data-testid="stTextInput"] input:focus,
65
  div[data-testid="stTextInput"] input:active {
 
77
  }
78
  #MainMenu, footer, header { visibility: hidden; }
79
 
 
80
  html, body, [data-testid="stAppViewContainer"], .main, .block-container,
81
  section[data-testid="stMain"], div[data-testid="stAppViewBlockContainer"] {
82
  scroll-behavior: smooth !important;
 
131
  transition: border-color 0.3s, box-shadow 0.3s;
132
  }
133
 
134
+ /* ── Global primary button (Search, Refine) ── */
135
  div[data-testid="stButton"] button[kind="primary"] {
136
  background-color: var(--gold) !important;
137
  border: none !important;
 
146
  background-color: var(--sepia) !important;
147
  }
148
 
149
+ /* ── Global secondary button (example pills, pagination) ── */
150
  div[data-testid="stButton"] button[kind="secondary"] {
151
  background: var(--tag-bg) !important;
152
  border: 1px solid var(--border) !important;
 
165
  font-style: normal !important;
166
  }
167
 
168
+ /* ── Feedback buttons β€” override the global secondary styles ── */
169
+ /* Unactivated state */
170
+ div[data-testid="stButton"] button[kind="secondary"].feedback-btn {
171
+ width: auto !important;
172
+ min-width: 0 !important;
173
+ white-space: nowrap !important;
174
+ padding: 0.2rem 0.75rem !important;
175
+ font-size: 0.72rem !important;
176
+ font-style: normal !important;
177
+ border-radius: 20px !important;
178
+ letter-spacing: 0.04em !important;
179
+ color: var(--muted) !important;
180
+ border-color: var(--border) !important;
181
+ }
182
+ div[data-testid="stButton"] button[kind="secondary"].feedback-btn:hover {
183
+ color: var(--gold) !important;
184
+ border-color: var(--gold) !important;
185
+ background: var(--tag-bg) !important;
186
+ font-style: normal !important;
187
+ }
188
+ /* Activated (primary) state */
189
+ div[data-testid="stButton"] button[kind="primary"].feedback-btn {
190
+ width: auto !important;
191
+ min-width: 0 !important;
192
+ white-space: nowrap !important;
193
+ padding: 0.2rem 0.75rem !important;
194
+ font-size: 0.72rem !important;
195
+ border-radius: 20px !important;
196
+ letter-spacing: 0.04em !important;
197
+ }
198
+
199
+ /* Feedback row: shrink columns to hug content */
200
+ div[data-testid="stHorizontalBlock"]:has(button.feedback-btn) {
201
+ gap: 0.4rem !important;
202
+ margin-top: -0.25rem !important;
203
+ margin-bottom: 0.75rem !important;
204
+ align-items: center !important;
205
+ }
206
+ div[data-testid="stHorizontalBlock"]:has(button.feedback-btn)
207
+ > div[data-testid="stColumn"] {
208
+ flex: 0 0 auto !important;
209
+ width: auto !important;
210
+ min-width: 0 !important;
211
+ padding: 0 !important;
212
+ }
213
+ /* The spacer column should still stretch */
214
+ div[data-testid="stHorizontalBlock"]:has(button.feedback-btn)
215
+ > div[data-testid="stColumn"]:last-child {
216
+ flex: 1 1 auto !important;
217
+ }
218
+
219
  .masthead {
220
  text-align: center;
221
  padding: 3.5rem 1rem 2rem;
 
280
  .result-card {
281
  background: var(--card-bg); border: 1px solid var(--border);
282
  border-radius: 4px; padding: 1.4rem 1.6rem;
283
+ margin-bottom: 0.4rem; scroll-margin-top: 80px;
284
  transition: border-color 0.3s, box-shadow 0.3s;
285
  }
286
  .result-card:hover { border-color: var(--gold); box-shadow: 0 4px 18px rgba(200,151,58,0.12); }
 
321
  .no-results-icon { font-size:3rem; margin-bottom:1rem; }
322
  .no-results-title { font-family:'Playfair Display',serif; font-size:1.4rem; color:var(--ink); margin-bottom:0.5rem; }
323
 
 
324
  div[data-testid="stForm"] div[data-testid="stHorizontalBlock"] {
325
  align-items: flex-end !important;
326
  }
327
 
 
 
 
 
 
328
  .bpl-footer {
329
  text-align:center; padding:2.5rem 1rem 1rem;
330
  border-top:1px solid var(--border); margin-top:3rem;
 
332
  }
333
  .bpl-footer strong { color: var(--sepia); }
334
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
335
  [data-testid="InputInstructions"],
336
  [data-testid="stTextAreaInstructions"],
337
  [data-testid="stWidgetInstructions"],
 
339
  div[data-testid="stTextInput"] small {
340
  display: none !important;
341
  }
 
 
 
 
 
 
 
 
 
 
 
 
342
  </style>
343
  """, unsafe_allow_html=True)
344
 
 
354
 
355
  # ── Helpers ───────────────────────────────────────────────────────────────────
356
  def linkify_citations(text: str, num_docs: int) -> str:
 
357
  def replace(match):
358
  n = int(match.group(1))
359
  if 1 <= n <= num_docs:
 
404
  'border-radius:4px;margin-bottom:0.8rem;" />'
405
  if r.get("thumbnail", "").startswith("https://") else ""
406
  )
 
407
  full_text = r.get("full_text", "")
408
  if full_text and len(full_text) > 300:
409
  expander = (
 
444
  for k, v in [
445
  ("query", ""), ("results", None), ("searched", False),
446
  ("context", ""), ("latency_ms", 0), ("_last_ran", ""), ("page", 0),
447
+ ("query_id", None),
448
+ ("docs", []),
449
+ ("thumbs", {}),
450
+ ("missing_text", ""),
451
+ ("refined_with", []),
452
+ ("_scroll_to_top", False),
453
  ]:
454
  if k not in st.session_state:
455
  st.session_state[k] = v
456
 
 
457
  if "session_id" not in st.session_state:
458
  st.session_state["session_id"] = str(uuid.uuid4())
459
 
460
 
 
461
  # ── Masthead ──────────────────────────────────────────────────────────────────
462
  st.markdown("""
463
  <div class="masthead">
 
502
  pill_clicked = q
503
 
504
 
 
505
  # ── Determine active query ────────────────────────────────────────────────────
506
  if pill_clicked:
507
  st.session_state.query = pill_clicked
 
543
  st.markdown('<hr class="divider">', unsafe_allow_html=True)
544
 
545
  if results:
 
546
  if st.session_state["refined_with"]:
547
  chips = " Β· ".join(html.escape(q) for q in st.session_state["refined_with"])
548
  st.markdown(
 
551
  unsafe_allow_html=True,
552
  )
553
 
 
554
  if st.session_state["_scroll_to_top"]:
555
  st.session_state["_scroll_to_top"] = False
556
  components.html(
 
588
  unsafe_allow_html=True,
589
  )
590
 
 
 
 
 
 
 
591
  PAGE_SIZE = 10
592
  total_pages = max(1, (len(results) + PAGE_SIZE - 1) // PAGE_SIZE)
593
  page = st.session_state["page"]
 
598
 
599
  page_docs = st.session_state.docs[start:end]
600
  for i, (r, doc) in enumerate(zip(page_results, page_docs), start=start + 1):
601
+ # Card and feedback grouped together
602
+ with st.container():
603
+ st.markdown(build_card_html(r, i), unsafe_allow_html=True)
604
+
605
+ # ── Feedback row ──────────────────────────────────────────
606
+ current = st.session_state["thumbs"].get(doc.ark_id)
607
+
608
+ # Use a narrow 3-column layout: [helpful btn] [not relevant btn] [spacer]
609
+ fb_col1, fb_col2, fb_spacer = st.columns([1, 1.4, 8])
610
+
611
+ with fb_col1:
612
+ up_type = "primary" if current == "up" else "secondary"
613
+ if st.button(
614
+ "βœ“ Helpful",
615
+ key=f"up_{i}_{doc.ark_id}",
616
+ type=up_type,
617
+ help="Mark as helpful",
618
+ use_container_width=True,
619
+ ):
620
+ st.session_state["thumbs"][doc.ark_id] = "up"
621
+ log_feedback(
622
+ query_id = st.session_state["query_id"],
623
+ ark_id = doc.ark_id,
624
+ signal = "up",
625
+ session_id = st.session_state["session_id"],
626
+ raw_query = st.session_state["query"],
627
+ )
628
+ st.rerun()
629
+
630
+ with fb_col2:
631
+ down_type = "primary" if current == "down" else "secondary"
632
+ if st.button(
633
+ "βœ— Not relevant",
634
+ key=f"down_{i}_{doc.ark_id}",
635
+ type=down_type,
636
+ help="Mark as not relevant",
637
+ use_container_width=True,
638
+ ):
639
+ st.session_state["thumbs"][doc.ark_id] = "down"
640
+ log_feedback(
641
+ query_id = st.session_state["query_id"],
642
+ ark_id = doc.ark_id,
643
+ signal = "down",
644
+ session_id = st.session_state["session_id"],
645
+ raw_query = st.session_state["query"],
646
+ )
647
+ st.rerun()
648
+
649
+ # Small gap between cards
650
+ st.markdown('<div style="height:0.6rem"></div>', unsafe_allow_html=True)
651
 
652
  # ── Pagination controls ───────────────────────────────────────────────
653
  if total_pages > 1:
 
673
  st.session_state["page"] += 1
674
  st.rerun()
675
 
676
+ # ── Human-in-the-loop refinement ──────────────────────────────────
677
  st.markdown('<hr class="divider">', unsafe_allow_html=True)
678
  st.markdown(
679
  '<div class="search-label">Didn\'t find any relevant results?</div>',
 
692
  placeholder="e.g. photographs of JFK as a senator in 1958, not newspaper clippings",
693
  label_visibility="collapsed",
694
  )
695
+ if st.button("Refine search", key="refine_btn", use_container_width=True):
 
696
  user_text = st.session_state["missing_text"].strip()
697
  if not user_text:
698
  st.info("Type a refined query before clicking refine.")
699
  else:
 
 
700
  log_feedback(
701
  query_id = st.session_state["query_id"],
702
  ark_id = "",