infinitylogesh commited on
Commit
8056215
·
verified ·
1 Parent(s): 2c5d0e7

GUI-Decisions Space

Browse files
Files changed (3) hide show
  1. ambient.css +48 -0
  2. app.py +41 -5
  3. intro.html +14 -0
ambient.css ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* The Ambient design system (vaan_db/site/public/assets/css/styles.css), the same tokens as the blog's
2
+ figures (systemone/blog/diagrams/_head.html): cream canvas, dark-brown ink, one orange accent. Orange is
3
+ the slot read, dark brown the base model writing its answer, taupe neutral structure. */
4
+ :root {
5
+ --bg:#fdf6f1; --bg-2:#f8ece4; --panel:#ffffff; --panel-2:#fbf1ea;
6
+ --ink-panel:#1c100b; --ink-panel-2:#2a170e; --on-ink:#fbeee6; --on-ink-muted:#bfa89c;
7
+ --ink:#1a110d; --ink2:#6b5850; --ink3:#9a877e; --rule:rgba(58,28,12,0.11); --rule-2:rgba(58,28,12,0.06); --dot:rgba(58,28,12,0.07);
8
+ --shadow:0 1px 2px rgba(58,28,12,0.05), 0 12px 32px -14px rgba(58,28,12,0.18);
9
+ --fast:#ff5a14; --fast-2:#ff7a2e; --fast-soft:#ffe5d8; /* ours: the slot read */
10
+ --slow:#3a2013; --slow-soft:#efe2d9; /* the baseline: writing */
11
+ --accent:#a3836f; --accent-soft:#f3e7df; /* neutral structure */
12
+ }
13
+ body, gradio-app, .gradio-container {
14
+ background:radial-gradient(var(--dot) 1.2px, transparent 1.2px) -12px -12px / 24px 24px, var(--bg) !important;
15
+ color:var(--ink); -webkit-font-smoothing:antialiased;
16
+ }
17
+ .gradio-container { max-width:1180px !important; margin:0 auto !important; }
18
+
19
+ /* header, as the site's sections: orange eyebrow, tight display title, muted lede */
20
+ .amb-head { padding:26px 4px 6px; }
21
+ .amb-head .eyebrow { font:600 11.5px "Inter",sans-serif; letter-spacing:.26em; text-transform:uppercase; color:var(--fast); margin:0 0 10px; }
22
+ .amb-head .title { font:800 34px/1.08 "Inter Tight","Inter",sans-serif; letter-spacing:-.03em; word-spacing:.04em; margin:0 0 12px; color:var(--ink); text-wrap:balance; }
23
+ .amb-head .title .fast { color:var(--fast); }
24
+ .amb-head .lede { color:var(--ink2); font-size:15.5px; line-height:1.6; margin:0 0 12px; max-width:54rem; }
25
+ .amb-head .links { font:500 12px "JetBrains Mono",monospace; letter-spacing:.06em; color:var(--ink3); margin:0; }
26
+ .amb-head .links a { color:var(--ink); text-decoration:none; border-bottom:1px solid var(--rule); }
27
+ .amb-head .links a:hover { color:var(--fast); border-color:var(--fast); }
28
+ .amb-note { color:var(--ink3); font-size:12.5px; line-height:1.55; margin:6px 4px 0; }
29
+ .amb-legend { display:flex; gap:18px; flex-wrap:wrap; font:500 12px "JetBrains Mono",monospace; color:var(--ink2); margin:2px 4px 0; }
30
+ .amb-legend i { display:inline-block; width:10px; height:10px; border-radius:50%; margin-right:6px; vertical-align:-1px; }
31
+
32
+ /* results: the read in a dark terminal panel, like the figures' .term */
33
+ .prose pre, .prose code { font-family:"JetBrains Mono",ui-monospace,monospace !important; }
34
+ .prose pre { background:var(--ink-panel) !important; color:var(--on-ink) !important; border-radius:12px !important;
35
+ border:0 !important; box-shadow:0 18px 36px -22px rgba(42,23,14,.6); }
36
+ .prose pre code { background:transparent !important; color:var(--on-ink) !important; }
37
+ .prose :not(pre) > code { background:var(--accent-soft) !important; color:var(--ink) !important; border-radius:6px; padding:1px 5px; }
38
+ .prose h3 { font:700 17px "Inter Tight","Inter",sans-serif !important; letter-spacing:-.02em; }
39
+ .prose strong { color:var(--ink); }
40
+ .prose table { font-variant-numeric:tabular-nums; border-collapse:collapse; background:var(--panel); }
41
+ .prose table, .prose th, .prose td { border:1px solid var(--rule) !important; }
42
+ .prose h2 { font:800 22px "Inter Tight","Inter",sans-serif !important; letter-spacing:-.03em; }
43
+ .prose th { color:var(--ink3); font:500 11px "JetBrains Mono",monospace !important; letter-spacing:.12em; text-transform:uppercase; }
44
+
45
+ /* tabs: an orange rule under the selected one */
46
+ button[role="tab"] { font:600 14px "Inter",sans-serif !important; color:var(--ink2) !important; }
47
+ button[role="tab"][aria-selected="true"] { color:var(--ink) !important; border-color:var(--fast) !important; }
48
+ button[role="tab"][aria-selected="true"]::after { background:var(--fast) !important; }
app.py CHANGED
@@ -18,7 +18,7 @@ from slotread.numbers import unwarp
18
 
19
  BASE = os.environ.get("BASE", "google/gemma-4-31B-it")
20
  ADAPTER = os.environ.get("ADAPTER", "infinitylogesh/GUI-Decisions-31B-LoRA")
21
- SLOT, VANILLA = (37, 99, 235), (234, 88, 12) # blue: slot reads; orange: the base model writing JSON
22
  MAX_PX = 3840 * 2160
23
  WARM = set() # functions that have run once in this process: the first call includes CUDA warm-up
24
 
@@ -109,7 +109,7 @@ def decide(image, instruction, previous, compare):
109
  md += (f"\n\n### Base model writing JSON: `{describe(va, vd, vtext)}`\n\n"
110
  f"Generating its answer took **{vms:.0f} ms** (Gemma 4's native `\"point\": [y, x]` format):\n\n"
111
  f"```\n{raw.strip()[:400]}\n```\n\n"
112
- "Blue: slot reads, with their x × y distribution as the heatmap. Orange: the base model's point.")
113
  label = {k: float(p) for k, p in zip(ACTIONS, probs(lp["action"]))}
114
  return out.convert("RGB"), md, label
115
 
@@ -137,11 +137,15 @@ def box(image, description):
137
  HERE = os.path.dirname(os.path.abspath(__file__))
138
  ex = lambda f: os.path.join(HERE, "examples", f)
139
  rows = lambda f: [l.split("\t") for l in open(ex(f)).read().splitlines() if l.strip()] # tab-separated examples
140
- INTRO = open(os.path.join(HERE, "intro.md")).read()
 
141
  HOW = open(os.path.join(HERE, "how.md")).read()
142
 
143
  with gr.Blocks(title="GUI-Decisions") as demo:
144
- gr.Markdown(INTRO)
 
 
 
145
  with gr.Tab("Computer use"):
146
  with gr.Row():
147
  with gr.Column():
@@ -152,6 +156,8 @@ with gr.Blocks(title="GUI-Decisions") as demo:
152
  go = gr.Button("Decide", variant="primary")
153
  with gr.Column():
154
  out_img = gr.Image(label="Decision")
 
 
155
  out_md = gr.Markdown()
156
  out_lab = gr.Label(label="action slot", num_top_classes=4)
157
  go.click(decide, [img, ins, prev, cmp], [out_img, out_md, out_lab])
@@ -170,5 +176,35 @@ with gr.Blocks(title="GUI-Decisions") as demo:
170
  with gr.Tab("How it works"):
171
  gr.Markdown(HOW)
172
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  if __name__ == "__main__":
174
- demo.queue().launch()
 
18
 
19
  BASE = os.environ.get("BASE", "google/gemma-4-31B-it")
20
  ADAPTER = os.environ.get("ADAPTER", "infinitylogesh/GUI-Decisions-31B-LoRA")
21
+ SLOT, VANILLA = (255, 90, 20), (58, 32, 19) # the Ambient theme: orange the slot read, dark brown the base model writing
22
  MAX_PX = 3840 * 2160
23
  WARM = set() # functions that have run once in this process: the first call includes CUDA warm-up
24
 
 
109
  md += (f"\n\n### Base model writing JSON: `{describe(va, vd, vtext)}`\n\n"
110
  f"Generating its answer took **{vms:.0f} ms** (Gemma 4's native `\"point\": [y, x]` format):\n\n"
111
  f"```\n{raw.strip()[:400]}\n```\n\n"
112
+ "Orange: the slot read, with its x × y distribution as the heatmap. Dark brown: the base model's point.")
113
  label = {k: float(p) for k, p in zip(ACTIONS, probs(lp["action"]))}
114
  return out.convert("RGB"), md, label
115
 
 
137
  HERE = os.path.dirname(os.path.abspath(__file__))
138
  ex = lambda f: os.path.join(HERE, "examples", f)
139
  rows = lambda f: [l.split("\t") for l in open(ex(f)).read().splitlines() if l.strip()] # tab-separated examples
140
+ INTRO = open(os.path.join(HERE, "intro.html")).read()
141
+ CSS = open(os.path.join(HERE, "ambient.css")).read()
142
  HOW = open(os.path.join(HERE, "how.md")).read()
143
 
144
  with gr.Blocks(title="GUI-Decisions") as demo:
145
+ gr.HTML(INTRO)
146
+ gr.HTML('<p class="amb-note">Timings here are this Space\'s shared GPU running bf16 in plain transformers. '
147
+ 'Served on vLLM (NVFP4, one RTX PRO 6000) a step takes ~150 ms, against ~470–550 ms for the same model '
148
+ 'writing its native JSON.</p>')
149
  with gr.Tab("Computer use"):
150
  with gr.Row():
151
  with gr.Column():
 
156
  go = gr.Button("Decide", variant="primary")
157
  with gr.Column():
158
  out_img = gr.Image(label="Decision")
159
+ gr.HTML('<div class="amb-legend"><span><i style="background:#ff5a14"></i>slot read · P(x) × P(y)</span>'
160
+ '<span><i style="background:#3a2013"></i>base model writing JSON</span></div>')
161
  out_md = gr.Markdown()
162
  out_lab = gr.Label(label="action slot", num_top_classes=4)
163
  go.click(decide, [img, ins, prev, cmp], [out_img, out_md, out_lab])
 
176
  with gr.Tab("How it works"):
177
  gr.Markdown(HOW)
178
 
179
+ # the Ambient theme: Inter / Inter Tight / JetBrains Mono, cream canvas, dark-brown ink, orange accent (light only)
180
+ ORANGE = gr.themes.Color(c50="#fff4ee", c100="#ffe5d8", c200="#ffc9ad", c300="#ffa77d", c400="#ff7a2e", c500="#ff5a14",
181
+ c600="#e64a08", c700="#bf3c06", c800="#8f2e07", c900="#5e1f06", c950="#3a1304")
182
+ WARM = gr.themes.Color(c50="#fdf6f1", c100="#f8ece4", c200="#efe2d9", c300="#d9c6ba", c400="#9a877e", c500="#6b5850",
183
+ c600="#4f3d35", c700="#3a2013", c800="#2a170e", c900="#1c100b", c950="#1a110d")
184
+ LIGHT = dict(
185
+ body_background_fill="#fdf6f1", body_text_color="#1a110d", body_text_color_subdued="#6b5850",
186
+ background_fill_primary="#ffffff", background_fill_secondary="#fbf1ea",
187
+ block_background_fill="#ffffff", block_border_color="rgba(58,28,12,0.11)", block_border_width="1px",
188
+ block_label_background_fill="#fbf1ea", block_label_text_color="#6b5850", block_title_text_color="#6b5850",
189
+ block_shadow="0 1px 2px rgba(58,28,12,0.05), 0 12px 32px -14px rgba(58,28,12,0.18)",
190
+ border_color_primary="rgba(58,28,12,0.11)", border_color_accent="#ff5a14",
191
+ input_background_fill="#fdf6f1", input_border_color="rgba(58,28,12,0.11)", input_border_color_focus="#ff7a2e",
192
+ button_primary_background_fill="#ff5a14", button_primary_background_fill_hover="#ff7a2e",
193
+ button_primary_text_color="#ffffff", button_primary_border_color="#ff5a14",
194
+ button_secondary_background_fill="#ffffff", button_secondary_background_fill_hover="#fbf1ea",
195
+ button_secondary_text_color="#1a110d", button_secondary_border_color="rgba(58,28,12,0.11)",
196
+ color_accent="#ff5a14", color_accent_soft="#ffe5d8", link_text_color="#ff5a14", link_text_color_hover="#e64a08",
197
+ checkbox_background_color_selected="#ff5a14", checkbox_border_color_selected="#ff5a14", slider_color="#ff5a14",
198
+ loader_color="#ff5a14", code_background_fill="#f3e7df", table_even_background_fill="#ffffff",
199
+ table_odd_background_fill="#fbf1ea", table_border_color="rgba(58,28,12,0.11)",
200
+ )
201
+ THEME = gr.themes.Base(primary_hue=ORANGE, secondary_hue=WARM, neutral_hue=WARM, radius_size=gr.themes.sizes.radius_lg,
202
+ font=[gr.themes.GoogleFont("Inter"), "system-ui", "sans-serif"],
203
+ font_mono=[gr.themes.GoogleFont("JetBrains Mono"), "ui-monospace", "monospace"])
204
+ THEME.set(block_radius="16px", **LIGHT, **{k + "_dark": v for k, v in LIGHT.items() if hasattr(THEME, k + "_dark")})
205
+ HEAD = ('<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700'
206
+ '&family=Inter+Tight:wght@700;800&family=JetBrains+Mono:wght@400;500;600&display=swap">')
207
+ LIGHT_ONLY = "() => { document.body.classList.remove('dark'); document.documentElement.classList.remove('dark'); }"
208
+
209
  if __name__ == "__main__":
210
+ demo.queue().launch(theme=THEME, css=CSS, head=HEAD, js=LIGHT_ONLY)
intro.html ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="amb-head">
2
+ <p class="eyebrow">Slot reading · GUI-Decisions</p>
3
+ <p class="title">Computer-use steps, <span class="fast">read</span> in one forward pass</p>
4
+ <p class="lede">Give it a screenshot and an instruction. Instead of <em>writing</em> <code>{"action": "click", "point": [412, 288]}</code>
5
+ token by token, the model fills a fixed template of slots, and every answer is read from one forward pass: the action, and the
6
+ point as a 256-bin distribution over x and over y. Nothing is decoded; the heatmap is that distribution.</p>
7
+ <p class="links">
8
+ <a href="https://logeshumapathi.com/blog/2026/10/06/slot-reading.html">blog post</a> ·
9
+ <a href="https://github.com/infinitylogesh/gui-decisions">code</a> ·
10
+ <a href="https://huggingface.co/infinitylogesh/GUI-Decisions-31B-LoRA">GUI-Decisions-31B-LoRA</a> ·
11
+ <a href="https://huggingface.co/infinitylogesh/GUI-Decisions-31B">GUI-Decisions-31B</a> ·
12
+ <a href="https://huggingface.co/infinitylogesh/GUI-Decisions-2B-LoRA">GUI-Decisions-2B-LoRA</a>
13
+ </p>
14
+ </div>