VoyagerXHF commited on
Commit
30d21c4
Β·
verified Β·
1 Parent(s): 8ac456b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +128 -11
app.py CHANGED
@@ -102,6 +102,29 @@ GEN_TOP_K = int(_gen_cfg.get('top_k', 1))
102
  GEN_REP_PENALTY = float(_gen_cfg.get('repetition_penalty', 1.0))
103
  STEER_DISPLAY_K = 10 # top-k candidates shown in the per-token probability panel
104
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  # ─── Device resolution ───────────────────────────────────────────────────────
106
 
107
  def _resolve_sae_device() -> torch.device:
@@ -502,18 +525,19 @@ def _steering_strength_from_mode(mode: str, diff_lookup, layer: int, feat_idx: i
502
 
503
  def cb_generate(prompt, layer, feat_idx, pos_str, steer_mode, compare_diff,
504
  steer_output_only, max_tok, greedy, top_k_tok, top_p, rep_penalty, temp,
505
- custom_strength=5.0):
506
  try:
507
  return _cb_generate_inner(prompt, layer, feat_idx, pos_str, steer_mode, compare_diff,
508
  steer_output_only, max_tok, greedy, top_k_tok, top_p, rep_penalty, temp,
509
- custom_strength)
510
  except gr.Error:
511
  raise
512
  except Exception as e:
513
  raise gr.Error(f"Generation failed: {e}")
514
 
515
 
516
- def cb_update_steer_preview(prompt: str, pos_str: str):
 
517
  """Tokenise the prompt and return an HTML token-position preview."""
518
  if not prompt.strip():
519
  return (
@@ -522,7 +546,13 @@ def cb_update_steer_preview(prompt: str, pos_str: str):
522
  )
523
  try:
524
  _, tokenizer = get_model()
525
- input_ids = tokenizer.encode(prompt)
 
 
 
 
 
 
526
  tokens = [tokenizer.decode([t]) for t in input_ids]
527
  positions = parse_positions(pos_str)
528
  return tokens_with_positions_html(tokens, positions)
@@ -706,7 +736,7 @@ def probs_to_html(tokens: list, chosen_probs: list, topk_data: list,
706
 
707
  def _cb_generate_inner(prompt, layer, feat_idx, pos_str, steer_mode, compare_diff,
708
  steer_output_only, max_tok, greedy, top_k_tok, top_p, rep_penalty, temp,
709
- custom_strength=5.0):
710
  global _orig_cache
711
  model, tokenizer = get_model()
712
  layer = int(layer)
@@ -716,7 +746,13 @@ def _cb_generate_inner(prompt, layer, feat_idx, pos_str, steer_mode, compare_dif
716
  strength = _steering_strength_from_mode(steer_mode, compare_diff, layer, feat_idx, float(custom_strength))
717
  positions = parse_positions(pos_str)
718
 
719
- input_ids = tokenizer.encode(prompt, return_tensors='pt').to(
 
 
 
 
 
 
720
  next(model.parameters()).device
721
  )
722
 
@@ -738,9 +774,9 @@ def _cb_generate_inner(prompt, layer, feat_idx, pos_str, steer_mode, compare_dif
738
  # The unsteered output depends only on the prompt and decoding parameters,
739
  # not on any steering inputs. Reuse the last result when those are unchanged.
740
  if greedy:
741
- orig_key = (prompt, int(max_tok), True)
742
  else:
743
- orig_key = (prompt, int(max_tok), False,
744
  int(top_k_tok), float(top_p), float(rep_penalty), float(temp))
745
 
746
  if _orig_cache is not None and _orig_cache['key'] == orig_key:
@@ -1495,6 +1531,24 @@ with gr.Blocks(title="Qwen-Scope Feature Explorer") as demo:
1495
  show_label=False,
1496
  )
1497
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1498
  gr.HTML('<span class="section-chip">Token Position Preview</span>'
1499
  '<span style="font-size:12px;color:#888;margin-left:8px;">'
1500
  'amber = steered &nbsp;Β·&nbsp; updates as you type'
@@ -1676,7 +1730,7 @@ with gr.Blocks(title="Qwen-Scope Feature Explorer") as demo:
1676
  inputs=[t2_prompt, t2_layer, t2_feat, t2_pos, t2_steer_mode, compare_diff_state,
1677
  t2_steer_output_only, t2_maxtok,
1678
  t2_greedy, t2_top_k_tok, t2_top_p, t2_rep_penalty,
1679
- t2_temperature, t2_custom_strength],
1680
  outputs=[t2_orig, t2_steered, t2_orig_probs, t2_steer_probs],
1681
  )
1682
  t3_run.click(
@@ -1699,12 +1753,12 @@ with gr.Blocks(title="Qwen-Scope Feature Explorer") as demo:
1699
  )
1700
  t2_prompt.change(
1701
  cb_update_steer_preview,
1702
- inputs=[t2_prompt, t2_pos],
1703
  outputs=[t2_pos_preview],
1704
  )
1705
  t2_pos.change(
1706
  cb_update_steer_preview,
1707
- inputs=[t2_prompt, t2_pos],
1708
  outputs=[t2_pos_preview],
1709
  )
1710
 
@@ -1763,6 +1817,69 @@ with gr.Blocks(title="Qwen-Scope Feature Explorer") as demo:
1763
  outputs=[t2_custom_strength],
1764
  )
1765
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1766
 
1767
  if __name__ == '__main__':
1768
  # Pre-load model onto GPU before accepting requests, so the first
 
102
  GEN_REP_PENALTY = float(_gen_cfg.get('repetition_penalty', 1.0))
103
  STEER_DISPLAY_K = 10 # top-k candidates shown in the per-token probability panel
104
 
105
+ # ─── Default chat templates (thinking / no-thinking) ─────────────────────────
106
+
107
+ _THINK_TEMPLATE = (
108
+ "<|im_start|>user\n"
109
+ "{content}"
110
+ "<|im_end|>\n"
111
+ "<|im_start|>assistant\n"
112
+ "<think>\n"
113
+ )
114
+
115
+ _NOTHINK_TEMPLATE = (
116
+ "<|im_start|>user\n"
117
+ "{content}"
118
+ "<|im_end|>\n"
119
+ "<|im_start|>assistant\n"
120
+ "<think>\n\n</think>\n\n"
121
+ )
122
+
123
+ def apply_default_template(prompt: str, think: bool) -> str:
124
+ """Wrap *prompt* in the ChatML template for thinking or no-thinking mode."""
125
+ tpl = _THINK_TEMPLATE if think else _NOTHINK_TEMPLATE
126
+ return tpl.format(content=prompt.strip())
127
+
128
  # ─── Device resolution ───────────────────────────────────────────────────────
129
 
130
  def _resolve_sae_device() -> torch.device:
 
525
 
526
  def cb_generate(prompt, layer, feat_idx, pos_str, steer_mode, compare_diff,
527
  steer_output_only, max_tok, greedy, top_k_tok, top_p, rep_penalty, temp,
528
+ custom_strength=5.0, apply_think=False, apply_nothink=False):
529
  try:
530
  return _cb_generate_inner(prompt, layer, feat_idx, pos_str, steer_mode, compare_diff,
531
  steer_output_only, max_tok, greedy, top_k_tok, top_p, rep_penalty, temp,
532
+ custom_strength, apply_think, apply_nothink)
533
  except gr.Error:
534
  raise
535
  except Exception as e:
536
  raise gr.Error(f"Generation failed: {e}")
537
 
538
 
539
+ def cb_update_steer_preview(prompt: str, pos_str: str,
540
+ apply_think: bool = False, apply_nothink: bool = False):
541
  """Tokenise the prompt and return an HTML token-position preview."""
542
  if not prompt.strip():
543
  return (
 
546
  )
547
  try:
548
  _, tokenizer = get_model()
549
+ if apply_think:
550
+ effective = apply_default_template(prompt, think=True)
551
+ elif apply_nothink:
552
+ effective = apply_default_template(prompt, think=False)
553
+ else:
554
+ effective = prompt
555
+ input_ids = tokenizer.encode(effective)
556
  tokens = [tokenizer.decode([t]) for t in input_ids]
557
  positions = parse_positions(pos_str)
558
  return tokens_with_positions_html(tokens, positions)
 
736
 
737
  def _cb_generate_inner(prompt, layer, feat_idx, pos_str, steer_mode, compare_diff,
738
  steer_output_only, max_tok, greedy, top_k_tok, top_p, rep_penalty, temp,
739
+ custom_strength=5.0, apply_think=False, apply_nothink=False):
740
  global _orig_cache
741
  model, tokenizer = get_model()
742
  layer = int(layer)
 
746
  strength = _steering_strength_from_mode(steer_mode, compare_diff, layer, feat_idx, float(custom_strength))
747
  positions = parse_positions(pos_str)
748
 
749
+ if apply_think:
750
+ effective_prompt = apply_default_template(prompt, think=True)
751
+ elif apply_nothink:
752
+ effective_prompt = apply_default_template(prompt, think=False)
753
+ else:
754
+ effective_prompt = prompt
755
+ input_ids = tokenizer.encode(effective_prompt, return_tensors='pt').to(
756
  next(model.parameters()).device
757
  )
758
 
 
774
  # The unsteered output depends only on the prompt and decoding parameters,
775
  # not on any steering inputs. Reuse the last result when those are unchanged.
776
  if greedy:
777
+ orig_key = (effective_prompt, int(max_tok), True)
778
  else:
779
+ orig_key = (effective_prompt, int(max_tok), False,
780
  int(top_k_tok), float(top_p), float(rep_penalty), float(temp))
781
 
782
  if _orig_cache is not None and _orig_cache['key'] == orig_key:
 
1531
  show_label=False,
1532
  )
1533
 
1534
+ t2_apply_think = gr.Checkbox(
1535
+ label="Apply default thinking template",
1536
+ value=False,
1537
+ info=(
1538
+ "Wrap the prompt in the ChatML format with thinking enabled "
1539
+ "(assistant prefill starts with <think>)."
1540
+ ),
1541
+ )
1542
+ t2_apply_nothink = gr.Checkbox(
1543
+ label="Apply default no-thinking template",
1544
+ value=False,
1545
+ info=(
1546
+ "Wrap the prompt in the ChatML format with thinking disabled "
1547
+ "(assistant prefill starts with <think>\\n\\n</think>)."
1548
+ ),
1549
+ )
1550
+ t2_template_info = gr.HTML(visible=False, value="")
1551
+
1552
  gr.HTML('<span class="section-chip">Token Position Preview</span>'
1553
  '<span style="font-size:12px;color:#888;margin-left:8px;">'
1554
  'amber = steered &nbsp;Β·&nbsp; updates as you type'
 
1730
  inputs=[t2_prompt, t2_layer, t2_feat, t2_pos, t2_steer_mode, compare_diff_state,
1731
  t2_steer_output_only, t2_maxtok,
1732
  t2_greedy, t2_top_k_tok, t2_top_p, t2_rep_penalty,
1733
+ t2_temperature, t2_custom_strength, t2_apply_think, t2_apply_nothink],
1734
  outputs=[t2_orig, t2_steered, t2_orig_probs, t2_steer_probs],
1735
  )
1736
  t3_run.click(
 
1753
  )
1754
  t2_prompt.change(
1755
  cb_update_steer_preview,
1756
+ inputs=[t2_prompt, t2_pos, t2_apply_think, t2_apply_nothink],
1757
  outputs=[t2_pos_preview],
1758
  )
1759
  t2_pos.change(
1760
  cb_update_steer_preview,
1761
+ inputs=[t2_prompt, t2_pos, t2_apply_think, t2_apply_nothink],
1762
  outputs=[t2_pos_preview],
1763
  )
1764
 
 
1817
  outputs=[t2_custom_strength],
1818
  )
1819
 
1820
+ # ── Template toggle: mutual exclusion + info panel + preview refresh ─
1821
+ _THINK_INFO_HTML = (
1822
+ '<div style="font-size:11px;color:#555;padding:6px 10px;'
1823
+ 'background:#eff6ff;border:1px solid #bfdbfe;border-radius:6px;'
1824
+ 'font-family:ui-monospace,monospace;white-space:pre-wrap;line-height:1.7;">'
1825
+ '&lt;|im_start|&gt;user\n'
1826
+ '&#123;your prompt&#125;&lt;|im_end|&gt;\n'
1827
+ '&lt;|im_start|&gt;assistant\n'
1828
+ '&lt;think&gt;\n'
1829
+ '</div>'
1830
+ )
1831
+ _NOTHINK_INFO_HTML = (
1832
+ '<div style="font-size:11px;color:#555;padding:6px 10px;'
1833
+ 'background:#f0fdf4;border:1px solid #bbf7d0;border-radius:6px;'
1834
+ 'font-family:ui-monospace,monospace;white-space:pre-wrap;line-height:1.7;">'
1835
+ '&lt;|im_start|&gt;user\n'
1836
+ '&#123;your prompt&#125;&lt;|im_end|&gt;\n'
1837
+ '&lt;|im_start|&gt;assistant\n'
1838
+ '&lt;think&gt;\n\n&lt;/think&gt;\n\n'
1839
+ '</div>'
1840
+ )
1841
+
1842
+ def _on_think_change(think_val, nothink_val, prompt, pos_str):
1843
+ if think_val:
1844
+ # Just checked: uncheck nothink, show think format, refresh preview
1845
+ return (gr.update(value=False),
1846
+ gr.update(visible=True, value=_THINK_INFO_HTML),
1847
+ cb_update_steer_preview(prompt, pos_str, True, False))
1848
+ elif nothink_val:
1849
+ # Unchecked by mutual exclusion β€” nothink is active; leave info+preview alone
1850
+ return gr.update(), gr.update(), gr.update()
1851
+ else:
1852
+ # Manually unchecked with nothing active β€” reset to raw
1853
+ return (gr.update(),
1854
+ gr.update(visible=False),
1855
+ cb_update_steer_preview(prompt, pos_str, False, False))
1856
+
1857
+ def _on_nothink_change(nothink_val, think_val, prompt, pos_str):
1858
+ if nothink_val:
1859
+ # Just checked: uncheck think, show nothink format, refresh preview
1860
+ return (gr.update(value=False),
1861
+ gr.update(visible=True, value=_NOTHINK_INFO_HTML),
1862
+ cb_update_steer_preview(prompt, pos_str, False, True))
1863
+ elif think_val:
1864
+ # Unchecked by mutual exclusion β€” think is active; leave info+preview alone
1865
+ return gr.update(), gr.update(), gr.update()
1866
+ else:
1867
+ # Manually unchecked with nothing active β€” reset to raw
1868
+ return (gr.update(),
1869
+ gr.update(visible=False),
1870
+ cb_update_steer_preview(prompt, pos_str, False, False))
1871
+
1872
+ t2_apply_think.change(
1873
+ fn=_on_think_change,
1874
+ inputs=[t2_apply_think, t2_apply_nothink, t2_prompt, t2_pos],
1875
+ outputs=[t2_apply_nothink, t2_template_info, t2_pos_preview],
1876
+ )
1877
+ t2_apply_nothink.change(
1878
+ fn=_on_nothink_change,
1879
+ inputs=[t2_apply_nothink, t2_apply_think, t2_prompt, t2_pos],
1880
+ outputs=[t2_apply_think, t2_template_info, t2_pos_preview],
1881
+ )
1882
+
1883
 
1884
  if __name__ == '__main__':
1885
  # Pre-load model onto GPU before accepting requests, so the first