David-stout commited on
Commit
71d5a71
·
verified ·
1 Parent(s): 5b2dbbc

Brand the demo like webAI and add the TwIL Intelligence Lab system prompt

Browse files
Files changed (6) hide show
  1. .gitattributes +1 -0
  2. .gitignore +3 -0
  3. app.py +250 -33
  4. brand/AppiCon.svg +378 -0
  5. brand/avatar.svg +4 -0
  6. brand/webai-cube-256.webp +3 -0
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ brand/webai-cube-256.webp filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ __pycache__/
2
+ *.pyc
3
+ .gradio/
app.py CHANGED
@@ -1,6 +1,7 @@
1
  import os
2
  import re
3
  from collections.abc import Iterator
 
4
  from threading import Thread
5
 
6
  import spaces
@@ -10,6 +11,10 @@ from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStream
10
 
11
  MODEL_ID = "webAI-Official/TwIL-LM3"
12
  MAX_INPUT_TOKEN_LENGTH = int(os.getenv("MAX_INPUT_TOKEN_LENGTH", "8192"))
 
 
 
 
13
 
14
  # Reasoning delimiters are non-special tokens (ids 128002 / 128003), so they
15
  # survive skip_special_tokens=True and Gradio can render them as a collapsible
@@ -22,38 +27,237 @@ _THINK_RE = re.compile(
22
  re.DOTALL,
23
  )
24
 
25
- TITLE = "# TwIL-LM3"
26
- DESCRIPTION = f"""
27
- Official demo of **[TwIL-LM3](https://huggingface.co/{MODEL_ID})**, webAI's 3B
28
- reasoning model for formal logic FOL translation, entailment, semantic
29
- parsing, Lean formalisation and critique.
30
-
31
- Built from [SmolLM3-3B](https://huggingface.co/HuggingFaceTB/SmolLM3-3B) via
32
- LoRA SFT, checkpoint fusion, WiSE-FT, and entropy-weighted GRPO. It writes a
33
- collapsible `{THINK_OPEN}` reasoning trace before the answer.
34
-
35
- **Temperature = 0** (greedy) reproduces the published numbers. Keep max new
36
- tokens at **2048+** so the thinking block is not cut off.
37
- """
38
 
39
- FOOTER = f"""
40
- ---
41
- Official Space for [{MODEL_ID}](https://huggingface.co/{MODEL_ID}) ·
42
- License: [webAI Non-Commercial License ver. 1.0](https://huggingface.co/{MODEL_ID})
 
 
 
 
43
  """
44
 
45
  PLACEHOLDER = """
46
- <div style="padding: 30px; text-align: center; display: flex; flex-direction: column; align-items: center;">
47
- <h1 style="font-size: 28px; margin-bottom: 2px; opacity: 0.55;">TwIL-LM3</h1>
48
- <p style="font-size: 18px; margin-bottom: 2px; opacity: 0.65;">Ask a formal-logic question…</p>
 
49
  </div>
50
  """
51
 
 
 
 
 
52
  CSS = """
53
- #col-container { max-width: 1100px; margin: 0 auto; }
54
- .dark .gradio-container { color: var(--body-text-color); }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  """
56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
58
  model = AutoModelForCausalLM.from_pretrained(
59
  MODEL_ID,
@@ -96,10 +300,12 @@ def chat_twil_lm3(
96
  top_p: float,
97
  enable_thinking: bool,
98
  ) -> Iterator[str]:
99
- conversation = []
100
  for msg in history or []:
101
  role = msg.get("role", "user")
102
  content = msg.get("content", "")
 
 
103
  if isinstance(content, list):
104
  content = ""
105
  if role == "assistant":
@@ -155,20 +361,29 @@ def chat_twil_lm3(
155
 
156
 
157
  chatbot = gr.Chatbot(
158
- height=450,
159
  placeholder=PLACEHOLDER,
160
- label="TwIL-LM3",
 
161
  allow_tags=["think"],
162
  line_breaks=False,
 
 
 
163
  )
164
 
165
- with gr.Blocks(theme=gr.themes.Soft(), css=CSS, fill_height=True) as demo:
166
  with gr.Column(elem_id="col-container"):
167
- gr.Markdown(TITLE)
168
- gr.Markdown(DESCRIPTION)
169
  gr.ChatInterface(
170
  fn=chat_twil_lm3,
171
  chatbot=chatbot,
 
 
 
 
 
 
172
  fill_height=True,
173
  concurrency_limit=1,
174
  additional_inputs_accordion=gr.Accordion(
@@ -217,9 +432,7 @@ with gr.Blocks(theme=gr.themes.Soft(), css=CSS, fill_height=True) as demo:
217
  [
218
  "Translate into first-order logic: Every student who studies hard passes at least one exam."
219
  ],
220
- [
221
- "Formalize in Lean 4: If n is even, then n^2 is even."
222
- ],
223
  [
224
  "Is 'All birds fly. Tweety is a bird. Therefore Tweety flies.' logically valid? Explain."
225
  ],
@@ -229,7 +442,11 @@ with gr.Blocks(theme=gr.themes.Soft(), css=CSS, fill_height=True) as demo:
229
  ],
230
  cache_examples=False,
231
  )
232
- gr.Markdown(FOOTER)
233
 
234
  if __name__ == "__main__":
235
- demo.launch()
 
 
 
 
 
1
  import os
2
  import re
3
  from collections.abc import Iterator
4
+ from pathlib import Path
5
  from threading import Thread
6
 
7
  import spaces
 
11
 
12
  MODEL_ID = "webAI-Official/TwIL-LM3"
13
  MAX_INPUT_TOKEN_LENGTH = int(os.getenv("MAX_INPUT_TOKEN_LENGTH", "8192"))
14
+ ASSETS = Path(__file__).resolve().parent / "brand"
15
+ ICON = ASSETS / "AppiCon.svg"
16
+ CUBE = ASSETS / "webai-cube-256.webp"
17
+ AVATAR = ASSETS / "avatar.svg"
18
 
19
  # Reasoning delimiters are non-special tokens (ids 128002 / 128003), so they
20
  # survive skip_special_tokens=True and Gradio can render them as a collapsible
 
27
  re.DOTALL,
28
  )
29
 
30
+ SYSTEM_PROMPT = (
31
+ "You are TwIL, a formal-logic reasoning model created by webAI Intelligence Lab. "
32
+ "You specialise in entailment, first-order logic, semantic parsing, Lean, and proof critique. "
33
+ f"Work through the problem in a {THINK_OPEN} block, then give a concise, precise answer."
34
+ )
 
 
 
 
 
 
 
 
35
 
36
+ HEADER = """
37
+ <div class="twil-header">
38
+ <img class="twil-mark" src="/gradio_api/file=brand/AppiCon.svg" alt="webAI" />
39
+ <div class="twil-header-copy">
40
+ <div class="twil-wordmark">webAI</div>
41
+ <div class="twil-product">TwIL-LM3 · Intelligence Lab</div>
42
+ </div>
43
+ </div>
44
  """
45
 
46
  PLACEHOLDER = """
47
+ <div class="twil-empty">
48
+ <img class="twil-cube" src="/gradio_api/file=brand/webai-cube-256.webp" alt="" />
49
+ <h1>What should we work on?</h1>
50
+ <p>TwIL-LM3 is webAI's formal-logic model — entailment, FOL, Lean, rule induction.</p>
51
  </div>
52
  """
53
 
54
+ FOOTER = """
55
+ <p class="twil-disclaimer">This is AI and it can make mistakes</p>
56
+ """
57
+
58
  CSS = """
59
+ :root {
60
+ --weba-bg: #ffffff;
61
+ --weba-subtle: #f4f4f4;
62
+ --weba-canvas: #f4f4f4;
63
+ --weba-fg: #161616;
64
+ --weba-muted: #737373;
65
+ --weba-secondary: #e8e8e8;
66
+ --weba-border: #e8e8e8;
67
+ --weba-composer: #ffffff;
68
+ --weba-primary: #232323;
69
+ --weba-primary-fg: #fafafa;
70
+ --weba-link: #2563eb;
71
+ --weba-radius: 12px;
72
+ }
73
+ .dark {
74
+ --weba-bg: #161616;
75
+ --weba-subtle: #232323;
76
+ --weba-canvas: #232323;
77
+ --weba-fg: #fafafa;
78
+ --weba-muted: #a8a8a8;
79
+ --weba-secondary: #323232;
80
+ --weba-border: rgba(255, 255, 255, 0.1);
81
+ --weba-composer: #161616;
82
+ --weba-primary: #e8e8e8;
83
+ --weba-primary-fg: #232323;
84
+ --weba-link: #3b82f6;
85
+ }
86
+ html, body, .gradio-container, .gradio-container .main,
87
+ .gradio-container .contain, .fillable, .gradio-container .column {
88
+ background: var(--weba-canvas) !important;
89
+ color: var(--weba-fg) !important;
90
+ }
91
+ .gradio-container {
92
+ max-width: 768px !important;
93
+ margin: 0 auto !important;
94
+ padding: 12px 16px 24px !important;
95
+ font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif !important;
96
+ }
97
+ .dark .gradio-container { color: var(--weba-fg); }
98
+ footer, .footer, .built-with, .settings-bar { display: none !important; }
99
+ a { color: var(--weba-link) !important; }
100
+
101
+ .twil-header {
102
+ display: flex;
103
+ align-items: center;
104
+ gap: 12px;
105
+ padding: 8px 4px 18px;
106
+ }
107
+ .twil-mark {
108
+ width: 28px;
109
+ height: 28px;
110
+ border-radius: 6px;
111
+ }
112
+ .twil-wordmark {
113
+ font-weight: 600;
114
+ font-size: 15px;
115
+ letter-spacing: -0.02em;
116
+ line-height: 1.2;
117
+ }
118
+ .twil-product {
119
+ font-size: 12px;
120
+ color: var(--weba-muted);
121
+ line-height: 1.3;
122
+ }
123
+ .twil-empty {
124
+ padding: 48px 24px 32px;
125
+ text-align: center;
126
+ display: flex;
127
+ flex-direction: column;
128
+ align-items: center;
129
+ }
130
+ .twil-cube {
131
+ width: 96px;
132
+ height: 96px;
133
+ margin-bottom: 28px;
134
+ }
135
+ .twil-empty h1 {
136
+ font-size: 28px;
137
+ font-weight: 500;
138
+ letter-spacing: -0.03em;
139
+ margin: 0 0 10px;
140
+ color: var(--weba-fg);
141
+ }
142
+ .twil-empty p {
143
+ margin: 0;
144
+ max-width: 28rem;
145
+ font-size: 16px;
146
+ line-height: 1.5;
147
+ color: var(--weba-muted);
148
+ }
149
+ .twil-disclaimer {
150
+ margin: 10px 0 0;
151
+ text-align: center;
152
+ font-size: 11px;
153
+ color: var(--weba-muted);
154
+ opacity: 0.85;
155
+ }
156
+
157
+ #twil-chat {
158
+ background: transparent !important;
159
+ border: none !important;
160
+ box-shadow: none !important;
161
+ }
162
+ #twil-chat .wrapper, #twil-chat .bubble-wrap, #twil-chat .message-wrap {
163
+ background: transparent !important;
164
+ }
165
+ #twil-chat .user, #twil-chat .message.user, #twil-chat .user-row .message,
166
+ #twil-chat .bubble.user, #twil-chat [data-testid="user"] {
167
+ background: var(--weba-secondary) !important;
168
+ color: var(--weba-fg) !important;
169
+ border: none !important;
170
+ border-radius: 12px !important;
171
+ }
172
+ #twil-chat .bot, #twil-chat .message.bot, #twil-chat .bot-row .message,
173
+ #twil-chat .bubble.bot {
174
+ background: transparent !important;
175
+ border: none !important;
176
+ box-shadow: none !important;
177
+ }
178
+
179
+ #twil-input textarea, #twil-input input, .input-container textarea {
180
+ background: var(--weba-composer) !important;
181
+ color: var(--weba-fg) !important;
182
+ border: 1px solid var(--weba-border) !important;
183
+ border-radius: 999px !important;
184
+ padding: 14px 18px !important;
185
+ font-size: 16px !important;
186
+ box-shadow: none !important;
187
+ }
188
+ .input-container, #twil-input {
189
+ background: transparent !important;
190
+ border: none !important;
191
+ box-shadow: none !important;
192
+ }
193
+
194
+ button.primary, .primary {
195
+ background: var(--weba-primary) !important;
196
+ color: var(--weba-primary-fg) !important;
197
+ border: none !important;
198
+ border-radius: 999px !important;
199
+ }
200
+ button.secondary, .secondary {
201
+ background: var(--weba-secondary) !important;
202
+ color: var(--weba-fg) !important;
203
+ border: 1px solid var(--weba-border) !important;
204
+ border-radius: 999px !important;
205
+ }
206
+
207
+ .examples, .samples {
208
+ gap: 8px !important;
209
+ }
210
+ .examples button, .sample {
211
+ background: var(--weba-bg) !important;
212
+ color: var(--weba-fg) !important;
213
+ border: 1px solid var(--weba-border) !important;
214
+ border-radius: 999px !important;
215
+ font-size: 13px !important;
216
+ }
217
+ .accordion, .label-wrap {
218
+ background: transparent !important;
219
+ border-color: var(--weba-border) !important;
220
+ color: var(--weba-muted) !important;
221
+ }
222
  """
223
 
224
+ THEME = gr.themes.Base(
225
+ primary_hue="zinc",
226
+ secondary_hue="zinc",
227
+ neutral_hue="zinc",
228
+ font=[gr.themes.GoogleFont("Inter"), "ui-sans-serif", "system-ui", "sans-serif"],
229
+ font_mono=["ui-monospace", "SFMono-Regular", "Menlo", "monospace"],
230
+ radius_size=gr.themes.sizes.radius_lg,
231
+ ).set(
232
+ body_background_fill="#f4f4f4",
233
+ body_background_fill_dark="#232323",
234
+ body_text_color="#161616",
235
+ body_text_color_dark="#fafafa",
236
+ background_fill_primary="#ffffff",
237
+ background_fill_primary_dark="#161616",
238
+ background_fill_secondary="#e8e8e8",
239
+ background_fill_secondary_dark="#323232",
240
+ border_color_primary="#e8e8e8",
241
+ border_color_primary_dark="rgba(255,255,255,0.1)",
242
+ block_background_fill="transparent",
243
+ block_background_fill_dark="transparent",
244
+ block_border_width="0px",
245
+ block_shadow="none",
246
+ block_shadow_dark="none",
247
+ button_primary_background_fill="#232323",
248
+ button_primary_background_fill_dark="#e8e8e8",
249
+ button_primary_text_color="#fafafa",
250
+ button_primary_text_color_dark="#232323",
251
+ button_secondary_background_fill="#e8e8e8",
252
+ button_secondary_background_fill_dark="#323232",
253
+ button_secondary_text_color="#161616",
254
+ button_secondary_text_color_dark="#fafafa",
255
+ input_background_fill="#ffffff",
256
+ input_background_fill_dark="#161616",
257
+ input_border_color="#e8e8e8",
258
+ input_border_color_dark="rgba(255,255,255,0.1)",
259
+ )
260
+
261
  tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
262
  model = AutoModelForCausalLM.from_pretrained(
263
  MODEL_ID,
 
300
  top_p: float,
301
  enable_thinking: bool,
302
  ) -> Iterator[str]:
303
+ conversation = [{"role": "system", "content": SYSTEM_PROMPT}]
304
  for msg in history or []:
305
  role = msg.get("role", "user")
306
  content = msg.get("content", "")
307
+ if role == "system":
308
+ continue
309
  if isinstance(content, list):
310
  content = ""
311
  if role == "assistant":
 
361
 
362
 
363
  chatbot = gr.Chatbot(
364
+ height=520,
365
  placeholder=PLACEHOLDER,
366
+ label="",
367
+ show_label=False,
368
  allow_tags=["think"],
369
  line_breaks=False,
370
+ layout="bubble",
371
+ avatar_images=(None, str(AVATAR) if AVATAR.exists() else None),
372
+ elem_id="twil-chat",
373
  )
374
 
375
+ with gr.Blocks(fill_height=True) as demo:
376
  with gr.Column(elem_id="col-container"):
377
+ gr.HTML(HEADER)
 
378
  gr.ChatInterface(
379
  fn=chat_twil_lm3,
380
  chatbot=chatbot,
381
+ textbox=gr.Textbox(
382
+ placeholder="Ask webAI anything…",
383
+ show_label=False,
384
+ container=False,
385
+ elem_id="twil-input",
386
+ ),
387
  fill_height=True,
388
  concurrency_limit=1,
389
  additional_inputs_accordion=gr.Accordion(
 
432
  [
433
  "Translate into first-order logic: Every student who studies hard passes at least one exam."
434
  ],
435
+ ["Formalize in Lean 4: If n is even, then n^2 is even."],
 
 
436
  [
437
  "Is 'All birds fly. Tweety is a bird. Therefore Tweety flies.' logically valid? Explain."
438
  ],
 
442
  ],
443
  cache_examples=False,
444
  )
445
+ gr.HTML(FOOTER)
446
 
447
  if __name__ == "__main__":
448
+ demo.launch(
449
+ theme=THEME,
450
+ css=CSS,
451
+ allowed_paths=[str(ASSETS), str(ASSETS.parent)],
452
+ )
brand/AppiCon.svg ADDED
brand/avatar.svg ADDED
brand/webai-cube-256.webp ADDED

Git LFS Details

  • SHA256: d4cc93f2f9f45d06eabc845734c3ffd182eb4e58f2169b6605cf02e06e3a57e4
  • Pointer size: 131 Bytes
  • Size of remote file: 850 kB