David-stout commited on
Commit
ae2e88d
·
verified ·
1 Parent(s): 6867ac6

Add Showcase tab: one-click real-world argument analysis gallery

Browse files
Files changed (1) hide show
  1. app.py +269 -38
app.py CHANGED
@@ -55,6 +55,64 @@ CHIPS = [
55
  ),
56
  ]
57
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  HEADER = """
59
  <div class="twil-header">
60
  <img class="twil-mark" src="/gradio_api/file=brand/AppiCon.svg" alt="webAI" />
@@ -387,6 +445,148 @@ footer, .footer, .built-with, .settings, .settings-bar, .show-api,
387
  color: var(--weba-muted);
388
  flex-shrink: 0;
389
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
390
  """
391
 
392
  THEME = gr.themes.Base(
@@ -614,44 +814,57 @@ def generate_reply(history, max_new_tokens, temperature, top_p, enable_thinking)
614
  with gr.Blocks(fill_height=True, fill_width=True, elem_id="app-root") as demo:
615
  with gr.Column(elem_id="app-shell"):
616
  gr.HTML(HEADER)
617
- chatbot = gr.Chatbot(
618
- value=[],
619
- placeholder=PLACEHOLDER,
620
- label="",
621
- show_label=False,
622
- layout="bubble",
623
- avatar_images=(None, str(AVATAR) if AVATAR.exists() else None),
624
- allow_tags=["think"],
625
- reasoning_tags=[(THINK_OPEN, THINK_CLOSE)],
626
- buttons=None,
627
- editable=False,
628
- line_breaks=False,
629
- elem_id="twil-chat",
630
- scale=1,
631
- height="100%",
632
- )
633
- with gr.Row(elem_id="chips-row") as chips_row:
634
- chip_btns = [
635
- gr.Button(label, variant="secondary", size="sm", elem_classes=["twil-chip"])
636
- for label, _ in CHIPS
637
- ]
638
- with gr.Row(elem_id="composer-row"):
639
- prompt = gr.Textbox(
640
- placeholder="Ask webAI anything…",
641
- show_label=False,
642
- container=False,
643
- lines=2,
644
- max_lines=2,
645
- elem_id="twil-input",
646
- scale=8,
647
- )
648
- send = gr.Button("↑", elem_id="send-btn", scale=0)
649
- with gr.Accordion("Parameters", open=False, elem_id="params-box"):
650
- max_new_tokens = gr.Slider(256, 4096, value=2048, step=256, label="Max new tokens")
651
- temperature = gr.Slider(0, 1.5, value=0, step=0.05, label="Temperature (0 = greedy)")
652
- top_p = gr.Slider(0.1, 1.0, value=0.95, step=0.05, label="Top-p")
653
- enable_thinking = gr.Checkbox(value=True, label="Enable thinking")
654
- gr.HTML('<p class="twil-disclaimer">This is AI and it can make mistakes</p>')
 
 
 
 
 
 
 
 
 
 
 
 
 
655
 
656
  send.click(
657
  queue_message,
@@ -680,6 +893,24 @@ with gr.Blocks(fill_height=True, fill_width=True, elem_id="app-root") as demo:
680
  for btn, (_, template) in zip(chip_btns, CHIPS):
681
  btn.click(lambda t=template: t, outputs=prompt)
682
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
683
  if __name__ == "__main__":
684
  demo.launch(
685
  theme=THEME,
 
55
  ),
56
  ]
57
 
58
+ SHOWCASE_TEMPLATE = (
59
+ "Analyze this argument: extract the premises and the conclusion, translate them "
60
+ "into first-order logic, state whether the argument is valid, and name any fallacy.\n\n"
61
+ 'Argument: "{argument}"'
62
+ )
63
+
64
+ SHOWCASE = [
65
+ {
66
+ "kicker": "Viral tweet",
67
+ "quote": "The streets are wet this morning, and rain always makes the streets wet. So it obviously rained last night.",
68
+ "hint": "Can wet streets prove rain?",
69
+ },
70
+ {
71
+ "kicker": "School board speech",
72
+ "quote": "If we let students retake this one exam, soon they will demand to retake every exam, and before long no grade at this school will mean anything.",
73
+ "hint": "Does one retake doom every grade?",
74
+ },
75
+ {
76
+ "kicker": "Supplement ad",
77
+ "quote": "Our formula is 100% natural, and nature knows best. That means it is completely safe for your body.",
78
+ "hint": "Does natural imply safe?",
79
+ },
80
+ {
81
+ "kicker": "Campaign rally",
82
+ "quote": "Either you support this bill or you don't care about public safety. You oppose the bill, so you don't care about public safety.",
83
+ "hint": "Are those really the only options?",
84
+ },
85
+ {
86
+ "kicker": "Toothpaste commercial",
87
+ "quote": "4 out of 5 dentists we surveyed recommend SparkleDent, and experts know best. You should switch to SparkleDent today.",
88
+ "hint": "What is the survey hiding?",
89
+ },
90
+ {
91
+ "kicker": "HR policy memo",
92
+ "quote": "Every employee who completes the security training receives a certificate. Sam completed the security training. Therefore Sam receives a certificate.",
93
+ "hint": "One of these six actually holds up.",
94
+ },
95
+ ]
96
+
97
+ SHOWCASE_INTRO = """
98
+ <div class="twil-showcase-intro">
99
+ <h2>Can TwIL spot the flaw?</h2>
100
+ <p>Six arguments from the wild. One click and TwIL extracts the premises, translates
101
+ them to first-order logic, and rules on validity. Five are broken — one holds up.</p>
102
+ </div>
103
+ """
104
+
105
+
106
+ def _card_html(case: dict) -> str:
107
+ return (
108
+ '<div class="twil-card-body">'
109
+ f'<div class="twil-card-kicker">{case["kicker"]}</div>'
110
+ f'<div class="twil-card-quote">&ldquo;{case["quote"]}&rdquo;</div>'
111
+ f'<div class="twil-card-hint">{case["hint"]}</div>'
112
+ "</div>"
113
+ )
114
+
115
+
116
  HEADER = """
117
  <div class="twil-header">
118
  <img class="twil-mark" src="/gradio_api/file=brand/AppiCon.svg" alt="webAI" />
 
445
  color: var(--weba-muted);
446
  flex-shrink: 0;
447
  }
448
+
449
+ /* Tabs shell: keep the chat layout filling the viewport */
450
+ #twil-tabs {
451
+ flex: 1 1 auto !important;
452
+ min-height: 0 !important;
453
+ display: flex !important;
454
+ flex-direction: column !important;
455
+ background: transparent !important;
456
+ border: none !important;
457
+ box-shadow: none !important;
458
+ }
459
+ #twil-tabs > .tab-wrapper,
460
+ #twil-tabs .tab-container,
461
+ #twil-tabs .tab-nav {
462
+ flex: 0 0 auto !important;
463
+ background: transparent !important;
464
+ border: none !important;
465
+ box-shadow: none !important;
466
+ justify-content: center !important;
467
+ }
468
+ #twil-tabs .tab-container button,
469
+ #twil-tabs .tab-nav button {
470
+ background: transparent !important;
471
+ border: none !important;
472
+ border-bottom: 2px solid transparent !important;
473
+ border-radius: 0 !important;
474
+ box-shadow: none !important;
475
+ color: var(--weba-muted) !important;
476
+ font-size: 13px !important;
477
+ padding: 6px 14px !important;
478
+ }
479
+ #twil-tabs .tab-container button.selected,
480
+ #twil-tabs .tab-nav button.selected {
481
+ color: var(--weba-fg) !important;
482
+ border-bottom-color: var(--weba-fg) !important;
483
+ }
484
+ #twil-tabs .tabitem {
485
+ flex: 1 1 auto !important;
486
+ min-height: 0 !important;
487
+ background: transparent !important;
488
+ border: none !important;
489
+ box-shadow: none !important;
490
+ padding: 0 !important;
491
+ }
492
+ #tab-chat > .gap, #tab-chat > .column,
493
+ #tab-chat, #tab-chat .column:has(> div > #twil-chat) {
494
+ height: 100% !important;
495
+ min-height: 0 !important;
496
+ }
497
+ #tab-chat > .gap, #tab-chat > .column {
498
+ display: flex !important;
499
+ flex-direction: column !important;
500
+ }
501
+ #tab-chat .block:has(#twil-chat),
502
+ #tab-chat div:has(> #twil-chat) {
503
+ flex: 1 1 auto !important;
504
+ min-height: 0 !important;
505
+ height: auto !important;
506
+ }
507
+ #tab-showcase {
508
+ overflow-y: auto !important;
509
+ }
510
+
511
+ /* Showcase cards */
512
+ .twil-showcase-intro {
513
+ max-width: 768px;
514
+ margin: 8px auto 4px;
515
+ text-align: center;
516
+ }
517
+ .twil-showcase-intro h2 {
518
+ font-size: 22px;
519
+ font-weight: 500;
520
+ letter-spacing: -0.02em;
521
+ margin: 0 0 6px;
522
+ color: var(--weba-fg);
523
+ }
524
+ .twil-showcase-intro p {
525
+ margin: 0 0 8px;
526
+ font-size: 14px;
527
+ line-height: 1.5;
528
+ color: var(--weba-muted);
529
+ }
530
+ .twil-card-row {
531
+ max-width: 900px !important;
532
+ width: 100% !important;
533
+ margin: 6px auto !important;
534
+ display: flex !important;
535
+ gap: 12px !important;
536
+ align-items: stretch !important;
537
+ background: transparent !important;
538
+ }
539
+ .twil-card {
540
+ background: var(--weba-composer) !important;
541
+ border: 1px solid var(--weba-border) !important;
542
+ border-radius: 16px !important;
543
+ box-shadow: none !important;
544
+ padding: 16px !important;
545
+ gap: 10px !important;
546
+ display: flex !important;
547
+ flex-direction: column !important;
548
+ justify-content: space-between !important;
549
+ min-height: 170px !important;
550
+ }
551
+ .twil-card > * { background: transparent !important; }
552
+ .twil-card-kicker {
553
+ font-size: 11px;
554
+ font-weight: 600;
555
+ letter-spacing: 0.06em;
556
+ text-transform: uppercase;
557
+ color: var(--weba-muted);
558
+ margin-bottom: 8px;
559
+ }
560
+ .twil-card-quote {
561
+ font-size: 14px;
562
+ line-height: 1.45;
563
+ color: var(--weba-fg);
564
+ margin-bottom: 8px;
565
+ }
566
+ .twil-card-hint {
567
+ font-size: 12px;
568
+ color: var(--weba-muted);
569
+ font-style: italic;
570
+ }
571
+ .twil-card-btn {
572
+ height: 32px !important;
573
+ border-radius: 999px !important;
574
+ border: 1px solid var(--weba-border) !important;
575
+ background: var(--weba-secondary) !important;
576
+ color: var(--weba-fg) !important;
577
+ box-shadow: none !important;
578
+ font-size: 13px !important;
579
+ font-weight: 500 !important;
580
+ align-self: flex-start !important;
581
+ padding: 0 16px !important;
582
+ width: auto !important;
583
+ min-width: 0 !important;
584
+ flex: 0 0 auto !important;
585
+ }
586
+ .twil-card-btn:hover {
587
+ background: var(--weba-fg) !important;
588
+ color: var(--weba-canvas) !important;
589
+ }
590
  """
591
 
592
  THEME = gr.themes.Base(
 
814
  with gr.Blocks(fill_height=True, fill_width=True, elem_id="app-root") as demo:
815
  with gr.Column(elem_id="app-shell"):
816
  gr.HTML(HEADER)
817
+ with gr.Tabs(elem_id="twil-tabs") as tabs:
818
+ with gr.Tab("Chat", id="chat", elem_id="tab-chat"):
819
+ chatbot = gr.Chatbot(
820
+ value=[],
821
+ placeholder=PLACEHOLDER,
822
+ label="",
823
+ show_label=False,
824
+ layout="bubble",
825
+ avatar_images=(None, str(AVATAR) if AVATAR.exists() else None),
826
+ allow_tags=["think"],
827
+ reasoning_tags=[(THINK_OPEN, THINK_CLOSE)],
828
+ buttons=None,
829
+ editable=False,
830
+ line_breaks=False,
831
+ elem_id="twil-chat",
832
+ scale=1,
833
+ height="100%",
834
+ )
835
+ with gr.Row(elem_id="chips-row") as chips_row:
836
+ chip_btns = [
837
+ gr.Button(label, variant="secondary", size="sm", elem_classes=["twil-chip"])
838
+ for label, _ in CHIPS
839
+ ]
840
+ with gr.Row(elem_id="composer-row"):
841
+ prompt = gr.Textbox(
842
+ placeholder="Ask webAI anything…",
843
+ show_label=False,
844
+ container=False,
845
+ lines=2,
846
+ max_lines=2,
847
+ elem_id="twil-input",
848
+ scale=8,
849
+ )
850
+ send = gr.Button("↑", elem_id="send-btn", scale=0)
851
+ with gr.Accordion("Parameters", open=False, elem_id="params-box"):
852
+ max_new_tokens = gr.Slider(256, 4096, value=2048, step=256, label="Max new tokens")
853
+ temperature = gr.Slider(0, 1.5, value=0, step=0.05, label="Temperature (0 = greedy)")
854
+ top_p = gr.Slider(0.1, 1.0, value=0.95, step=0.05, label="Top-p")
855
+ enable_thinking = gr.Checkbox(value=True, label="Enable thinking")
856
+ gr.HTML('<p class="twil-disclaimer">This is AI and it can make mistakes</p>')
857
+ with gr.Tab("Showcase", id="showcase", elem_id="tab-showcase"):
858
+ gr.HTML(SHOWCASE_INTRO)
859
+ card_btns = []
860
+ for start in range(0, len(SHOWCASE), 3):
861
+ with gr.Row(elem_classes=["twil-card-row"]):
862
+ for case in SHOWCASE[start : start + 3]:
863
+ with gr.Column(elem_classes=["twil-card"], scale=1, min_width=220):
864
+ gr.HTML(_card_html(case))
865
+ card_btns.append(
866
+ gr.Button("Analyze it", size="sm", elem_classes=["twil-card-btn"])
867
+ )
868
 
869
  send.click(
870
  queue_message,
 
893
  for btn, (_, template) in zip(chip_btns, CHIPS):
894
  btn.click(lambda t=template: t, outputs=prompt)
895
 
896
+ for btn, case in zip(card_btns, SHOWCASE):
897
+ case_prompt = SHOWCASE_TEMPLATE.format(argument=case["quote"])
898
+ btn.click(
899
+ lambda p=case_prompt: (p, gr.Tabs(selected="chat")),
900
+ outputs=[prompt, tabs],
901
+ ).then(
902
+ queue_message,
903
+ [prompt, chatbot],
904
+ [prompt, chatbot, chips_row],
905
+ show_progress="hidden",
906
+ ).then(
907
+ generate_reply,
908
+ [chatbot, max_new_tokens, temperature, top_p, enable_thinking],
909
+ chatbot,
910
+ concurrency_limit=1,
911
+ show_progress="minimal",
912
+ )
913
+
914
  if __name__ == "__main__":
915
  demo.launch(
916
  theme=THEME,